Good ending
Shared map
Astra route
Requires keeping the spare lantern through Season 1.
Guide for humans and agents editing MDX under src/content/docs/. Import walkthrough UI from @components/guide/. Ads use @components/ads/AdSlot.astro.
Write for someone playing with this tab open. Useful information first. Never invent dialogue, affection, costs, requirements, endings, or consequences.
/games/<game>//games/<game>/<story>//games/<game>/<story>/book-1/ # or season-1//games/<game>/<story>/book-1/chapter-1/Homepage → game → story → book (or season) → chapter (one MDX page per chapter).
Left sidebar nests books/seasons with Overview + chapters (collapsed: true; the current path auto-expands). In this book / In this season is still auto-built from sibling files for in-page switching.
Use GuideCard (not Starlight LinkCard) when a game, story, or book card should show a thumbnail:
import GuideCard from '@components/guide/GuideCard.astro';
<GuideCard title="League of Dreamers" href="/games/league-of-dreamers/" image="/images/games/league-of-dreamers/icon.jpeg" imageAlt="League of Dreamers app icon"/>Suggested asset layout:
public/images/games/<game>/icon.jpeg # app icon (cards + game overview)public/images/games/<game>/<story>/cover.jpg # story card / story overviewpublic/images/games/<game>/<story>/book-1.jpg # book card / book overviewOn game/story/book overview pages, show the same asset with class="game-icon" (square), class="story-cover" (horizontal cover band), or class="game-cover" (wide 16:9).
Prefer short tags chips over long descriptions on story cards:
<GuideCard title="Vampyrus Novus" href="/games/league-of-dreamers/vampyrus-novus/" image="/images/games/league-of-dreamers/vampyrus-novus/cover.jpg" imageAlt="Vampyrus Novus story cover" imageAspect="portrait" tags={['Mystic', 'Completed']}/>| Field | Purpose |
|---|---|
title |
Searchable page title, e.g. Book 1 Chapter 1 Choices — Vampyrus Novus |
sidebar.label |
Short nav label (Chapter 1, Overview) |
description |
Meta description |
game / story |
Shown by GuideMeta |
guideType |
overview · story · book · season · chapter · walkthrough · choices · collectibles · reference |
book / season / chapter |
Book or season label (match the URL segment), chapter label |
character |
Optional route focus |
spoilers |
none · minor · full — drives the spoiler banner in GuideMeta. Defaults to full on story, book, season, and chapter pages when omitted. Set none to suppress. |
platforms |
e.g. [iOS, Android] |
appStore / playStore |
Official store URLs; shown by StoreLinks on game overviews |
lastVerified |
Date — only after the guide was actually checked |
Use guideType: book (or season) on unit overviews and guideType: chapter on chapter pages so In this book / In this season works. Prefer book: frontmatter under /book-N/ paths and season: under /season-N/.
import GuideMeta from '@components/guide/GuideMeta.astro';import ChoiceList from '@components/guide/ChoiceList.astro';import Choice from '@components/guide/Choice.astro';import Requirement from '@components/guide/Requirement.astro';import Outcome from '@components/guide/Outcome.astro';import Notice from '@components/guide/Notice.astro';import Clue from '@components/guide/Clue.astro';import Spoiler from '@components/guide/Spoiler.astro';import Timed from '@components/guide/Timed.astro';import PathList from '@components/guide/PathList.astro';import PathStep from '@components/guide/PathStep.astro';import RouteSummary from '@components/guide/RouteSummary.astro';import EndingCard from '@components/guide/EndingCard.astro';import AdSlot from '@components/ads/AdSlot.astro';Use the first eleven imports on every chapter page. When you add a new guide component, add it to that chapter import block across all chapter MDX files and update this list.
Wraps a set of Choice cards. No visual chrome beyond spacing and list semantics.
| Prop | Type | Default | Notes |
|---|---|---|---|
label |
string | "Choices" |
Accessible name for the list |
timed |
boolean | — | Shows a Timed marker above the list |
Always put choices inside ChoiceList. Never place an ad inside the list or between a prompt and its choices.
Astra: “What do you say?”
<ChoiceList> <Choice result="affection" note="+1 Astra"> I wanted to see you too. </Choice> <Choice result="neutral"> Maybe another time. </Choice></ChoiceList>One dialogue option. Dialogue is the slot body — keep exact in-game wording. Status, cost, and CG sit in chips under the text. Never communicate status with colour alone (chips include labels).
| Prop | Type | Default | Notes |
|---|---|---|---|
result |
see below | neutral |
Outcome chip + marker style |
affection |
string | string[] | — | Character change, e.g. + Erich or - Erich. Array for multiple chips (["+ Irving", "- Erich"]). Text-only; colour follows result (pink / teal) or red for loss |
stat |
string | string[] | — | Stat / path change, e.g. + Mastery, - Mastery, + Child of Lilith. Array = multiple chips |
note |
string | — | Short path chip, e.g. No story effect — not prerequisites or toast text |
requires |
string | string[] | — | Prerequisite padlock chip(s). Hide gate: Only if you have Convincing Lies. Locked-but-visible: Needs 2 Phobia 💀 to select. Array = multiple chips |
notice |
string | string[] | — | In-game toast(s) for this option only. Array = several notifications from one pick |
noticeRequires |
string | string[] | — | Optional gate for each notice, matched by index (padlock chip on that toast) |
warning |
string | string[] | — | Guide warning(s) for this option only (warning colour). Array = several warnings |
positive |
string | string[] | — | Positive outcome(s) for this option only (green). Use instead of warning for good news |
negative |
string | string[] | — | Negative outcome(s) for this option only (red). Use instead of warning for bad path results |
cost |
number | string | — | Premium amount; shows cost chip when set |
currency |
string | diamonds |
Built-ins: diamonds, keys, tokens. Any other string is the label (e.g. emeralds) |
cg-img |
boolean | — | Use cg-img={true}. Shows CG Image chip with photo icon |
timed |
boolean | — | Use timed or timed={true} on a single option. Prefer <Timed /> or ChoiceList timed for whole prompts |
icon |
Starlight icon name | auto | Override marker. Default: relationship icons, else star when cost is set, else result default (circle / etc.) |
result values| Value | When to use | Chip label |
|---|---|---|
best |
Source material has a clear optimal answer | Best |
correct |
Single right answer (quiz / password / puzzle) | Correct |
incorrect |
Wrong answer in the same quiz | Incorrect |
affection |
Gains romance / intimate relationship | Affection |
friendship |
Gains friendship / platonic bond (teal card, not pink) | Friendship |
neutral |
No meaningful effect (default; chip hidden) | — |
negative |
Loses affection or hurts the path | Negative |
required |
Needed for a later scene or ending | Required |
premium |
Paid / premium framing without a numeric cost chip | Premium |
warning |
Risky, skips content, or soft-locks | Warning |
Use correct / incorrect only for single-answer quizzes. Prefer best only when the game or verified guide marks an optimal choice.
Use affection="+ Erich" / affection="- Erich" for character gains or losses. Pass an array when one choice hits multiple characters: affection={["+ Irving", "- Erich"]} — chips show each change, the card uses a neutral Mixed style (not pink heart), and pink/red stay on the chips. You can also set both positive and negative on the same choice. Use stat="+ Mastery" (or an array) for stats and path labels like + Child of Lilith. Free (no-cost) stat choices keep a regular card fill with a purple frame; paid choices keep the normal paid look and only show the stat chip. Pair relationship chips with result="affection" (pink) or result="friendship" (teal). Use note for short path chips like No story effect. Use requires for gates: Only if you have Convincing Lies when the option is hidden unless the condition is met; Needs 2 Phobia 💀 to select when it still shows but cannot be clicked without enough of the stat. Use notice="…" / notice={[…]} for toasts; pair with noticeRequires={[…]} when different toasts need different gates (matched by index). Use warning for caution callouts, positive / negative for good or bad consequences (or <Outcome type="…"> above/below a whole list).
When picking an option opens another choice prompt, nest a ChoiceList with slot="then" inside that Choice. Dialogue stays in the default slot; follow-ups go in then. Prefer this over a separate heading when the branch is short. For long branches, a new heading plus <Requirement> is still fine.
<ChoiceList> <Choice result="affection" affection="+ Irving" cost={30} currency="emeralds" > I want to talk to Irving alone. <ChoiceList slot="then" label="After talking to Irving alone"> <Choice result="neutral" note="No story effect"> Kiss Irving on the cheek. </Choice> <Choice result="neutral" note="No story effect"> Thank you. </Choice> </ChoiceList> </Choice> <Choice result="neutral" note="No story effect"> Finally, I will be able to make sense of everything alone. </Choice></ChoiceList><Choice result="affection" affection="+ Erich" cost={14} currency="emeralds" cg-img={true}> Slow your step and listen to how you feel.</Choice>
<Choice result="friendship" affection="+ Erich"> Offer to help with the maps.</Choice>
<Choice notice="Christian is deliberately trying to keep you from being pressured by Madame Irene."> Friendly, judicious, thoughtful.</Choice>
<Choice notice={[ "Irving surveyed the scene of Renata's death.", "You've found something useful.", ]}> Break into Renata's house.</Choice>
<Choice result="negative" affection="- Irving" notice="You gave the gendarmes reason to suspect Irving of murder." negative="Irving will be arrested in Book 2, Chapter 6."> Tell the truth about Irving.</Choice>
<Choice result="affection" affection="+ Irving" positive="Irving will not be arrested."> Lie.</Choice>
<Choice notice="Christian is trying to ingrate himself to Madame Irene and Mr. Meicher."> Windy, a bit cranky, and completely unfit to make serious decisions.</Choice>
<Choice> Another option with a longer toast. <span slot="notice">Full notification text can go in the notice slot.</span></Choice>
<Choice stat="+ Mastery"> Study the ledger again.</Choice>
<Choice stat={["+ Mastery", "+ Child of Lilith"]}> Accept the violet mark.</Choice>
<Choice stat="- Mastery"> Ignore the lesson.</Choice>
<Choice result="negative" affection="- Erich"> Turn away without a word.</Choice>
<Choice note="No story effect" cost={22} currency="diamonds"> Comfortable coat</Choice>
<Choice cost={40} currency="emeralds" requires="Only if you don't have Convincing Lies"> Refuse to continue the conversation.</Choice>
<Choice result="required" note="Unlocks scene" cost={1} currency="keys"> Open the spare drawer</Choice>Put cost in the chip (cost + currency), not inside the dialogue string.
I wanted to see you too.
Offer to help with the maps.
Study the ledger again.
Accept the violet mark.
Maybe another time.
Don’t contact me again.
Comfortable coat
Look at him a moment longer
The lantern keeper’s middle name.
The ferry password from last year.
Take the marked trail.
Keep the spare lantern.
Leave the lantern behind.
Call out a gate the player must meet. Prefer this over burying requirements in prose.
No props — body is the requirement text.
<Requirement>Reach 2 affection points before you leave the plaza, or the spare-key scene does not play.</Requirement>Scannable chapter → stat gates for story and book overviews. Reuses purple stat chips. Use or for path alternatives. Pass an array when one chapter has several gates.
| Prop | Type | Notes |
|---|---|---|
chapter |
string | Label, e.g. Chapter 6 |
href |
string | Chapter walkthrough URL |
needs |
string | string[] | Stat chip(s), e.g. 2 Mastery 🎓 |
or |
string | string[] | Alternate path chip(s) after or |
<StatReqList> <StatReq chapter="Chapter 6" href="/games/league-of-dreamers/vampyrus-novus/book-1/chapter-6/" needs="6 Eve's daughter 🐍" or="6 Child of Lilith 🌕" /></StatReqList>Guide tip for long-running systems (career paths, hidden meters, how a subplot works), or a branch that depends on an earlier skill/choice. Not an in-game toast (Notice) and not a hard gate (Requirement).
| Prop | Type | Default | Notes |
|---|---|---|---|
label |
string | "Clue" |
Override the kicker text |
requires |
string | — | Padlock gate, e.g. If you obtained the Detective skill |
note |
string | — | Extra path chip under the body, e.g. This does not affect the plot. |
<Clue>Throughout the story, you'll have choices that will help Christian decide on his career path by the end. If Christian's current position suits him, he'll open his own law practice. Otherwise, he'll enter government service.</Clue>
<Clue requires="If you obtained the Detective skill (Book 1, Chapter 3)"> Catalina will find the clues on her own, which will impress Irving.</Clue>
<Clue requires="If you don't have the Detective skill" note="This does not affect the plot."> Irving will be disappointed, but he will explain everything himself.</Clue>Marker for time-limited prompts. Place under a heading (above Steps, Clue, or freeform content), or set timed on a ChoiceList.
| Prop | Type | Default | Notes |
|---|---|---|---|
label |
string | "Timed" |
Override the chip text |
## Find the vampire clues
<Timed />
<Clue>Find three objects within the time limit…</Clue>
<ChoiceList timed> <Choice>Answer quickly.</Choice></ChoiceList>Timed
Consequence of a choice or path (guide commentary — not the in-game toast).
| Prop | Type | Default | Notes |
|---|---|---|---|
type |
positive · negative · neutral · secret · warning |
neutral |
Visual + accessible label |
requires |
string | string[] | — | Padlock gate(s), e.g. If Franz Ferdinand destroyed the medicine. Array = multiple chips |
note |
string | — | Extra path chip under the body |
cg-img |
boolean | — | Use cg-img={true}. Shows CG Image chip (same as Choice) |
id |
string | — | Fragment id for PathStep deep links |
Nest a PathList of PathStep links when the outcome depends on earlier choices — each step should deep-link to a Choice / Notice / Clue with a matching id.
<Outcome type="positive">Choosing “I wanted to see you too.” unlocks the rooftop lamp scene.</Outcome>
<Outcome type="warning">The answer will affect your future and Irving's future.</Outcome>
<Outcome type="positive" requires={[ "If Franz Ferdinand destroyed the medicine in Book 3, Chapter 7", "Be on Christian's romantic route.", ]}> **Moritz escaped — cure can be obtained.**</Outcome>
<Outcome type="positive"> **Vampiriate +1** — Fragment removed from Erich's chest.
<PathList> <PathStep chapter="Book 2 Chapter 5" href="/games/league-of-dreamers/vampyrus-novus/book-2/chapter-5/#remove-erich-fragment" > Suggest removing the fragment </PathStep> </PathList></Outcome>Numbered links to the prior choices (or chapter notes) that lead to an outcome. Nest inside Outcome. Works without JavaScript.
No props — slot only. Renders a How to reach this kicker and an ordered list.
| Prop | Type | Default | Notes |
|---|---|---|---|
href |
string | required | Chapter URL, usually with #choice-id |
chapter |
string | — | Short chip above the label, e.g. Book 2 Chapter 5 |
Give the target Choice, Notice, or Clue a matching id="kebab-case" so the link scrolls to it.
<PathList> <PathStep chapter="Book 3 Chapter 6" href="/games/league-of-dreamers/vampyrus-novus/book-3/chapter-6/#holzer-refuse" > I can't... I can't... </PathStep></PathList>In-game notification toast (composure lines, path changes, relationship pings, items). Always uses the info icon and a shared notification colour. Preserve exact in-game wording.
Toasts can fire after a choice, after a premium choice, or randomly in the scene — set when on a standalone <Notice> after the list when one toast applies to the list as a whole.
When different options show different toasts, put the toast on that option with notice="…" (or a slot="notice"). Do not put toast wording in note — note is for short path chips like “No story effect”.
Never place a toast between a prompt and its choices.
Use Outcome for guide commentary (“this unlocks X”). Use Notice / notice= for the toast the player sees in the game.
| Prop | Type | Default | Notes |
|---|---|---|---|
when |
choice · premium · random |
— | Optional. Shows a chip only when set: After free choice / After premium choice / Random in scene |
requires |
string | string[] | — | Optional padlock gate(s) for this toast (prior choice / relationship). Array = multiple chips. Not noticeRequires — that is Choice-only |
note |
string | — | Optional path chip under the toast (same look as Choice note) |
type |
see below | info |
Default kicker only — look stays the same |
label |
string | "Notification" / from type |
Override kicker text |
when values| Value | Chip | Meaning |
|---|---|---|
| (omit) | — | No timing chip |
choice |
After free choice | Fires after a free (non-premium) choice |
premium |
After premium choice | Fires after a paid / premium choice |
random |
Random in scene | Can appear during the scene without picking a specific option |
type values (kicker only)| Value | Default kicker |
|---|---|
info |
Notification |
path |
Path |
affection |
Relationship |
stat |
Stat |
item |
Item |
warning |
Warning |
<ChoiceList> <Choice notice="Christian is deliberately trying to keep you from being pressured by Madame Irene."> Friendly, judicious, thoughtful. </Choice> <Choice notice="Christian is trying to ingrate himself to Madame Irene and Mr. Meicher."> Windy, a bit cranky, and completely unfit to make serious decisions. </Choice></ChoiceList>
<ChoiceList> <Choice result="affection" affection="+ Erich" cost={14} currency="emeralds" cg-img={true}> Slow your step and listen to how you feel. </Choice></ChoiceList>
<Notice when="premium">You can’t keep your composure in the presence of Erich.</Notice>
<Notice>A plain notification with no timing chip.</Notice>
<Notice when="random" type="path">Path of Lilith</Notice>
<Notice when="choice" type="affection">Erich’s relationship has improved</Notice>Friendly, judicious, thoughtful.
Windy, a bit cranky, and completely unfit to make serious decisions.
Collapsed by default. Use for later-chapter requirements or ending spoilers.
| Prop | Type | Default |
|---|---|---|
label |
string | "Show spoiler" |
<Spoiler label="Show later requirement">You must reject the invitation during Chapter 9.</Spoiler>You must reject the invitation during Chapter 9.
Renders guide details from frontmatter (game, story, book/season, chapter, platforms, last verified, etc.). Optional props override frontmatter for that page.
When spoilers is minor or full (or defaults to full on story / book / season / chapter pages), it also shows a Spoiler warning banner above the details table. Place <GuideMeta /> near the top — after a one-line intro on chapter pages, and before long stat lists on story/book overviews — so readers see the warning first.
<GuideMeta />spoilers: full # or minor; use none to hide the bannerOptional summary block for character-route pages (not default top-level nav).
| Prop | Type | Notes |
|---|---|---|
character |
string | |
length |
string | Route length |
unlock |
string | Unlock requirement |
endings |
string | number | |
premium |
string | |
spoilers |
string |
Slot content can add freeform notes under the table.
<RouteSummary character="Astra" length="3 seasons" endings={2} unlock="Finish Season 1" />Route summary
Document an ending without inventing conditions you cannot verify.
| Prop | Type | Default | Notes |
|---|---|---|---|
title |
string | required | Ending name |
type |
good · normal · bad · secret · special |
normal |
|
character |
string | — | Shows as “Name route” |
<EndingCard type="good" title="Shared map" character="Astra">Requires keeping the spare lantern through Season 1.</EndingCard>Good ending
Shared map
Astra route
Requires keeping the spare lantern through Season 1.
| Prop | Type | Notes |
|---|---|---|
placement |
inline · leaderboard · sidebar |
Required |
unit |
string | AdSense unit ID. Use unit, never slot (reserved by Astro) |
Rules:
ChoiceList, or directly under a heading the player needs.PUBLIC_ADS_ENABLED is not true, renders nothing.<AdSlot placement="inline" unit="1234567890" />cost / currency chips; use affection="+ Name" / result="friendship" when needed; use cg-img={true} for CG unlocks; use Notice for in-game toasts after choices.lastVerified only after a real check.