Storyline: chapter structure + formatted Campaign Overview

The Storyline section is now a set of hand-written chapters. /storyline
lists them; /storyline/{slug} renders one inside a shell with a sticky
chapter nav and prev/next pager. Chapters are declared in
StorylineController::CHAPTERS, each pointing at a Twig partial under
templates/storyline/chapters/.

First chapter is the Brackenford Campaign Overview: the campaign-bible
text laid out as a long-form reading page -- numbered section headers,
a "by the numbers" / "the cast" quick-reference strip, pull-quotes for
in-world lines, GM callouts for the ticking clocks and the red herring,
and the escalation ladder. Storyline styles added to app.css.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Frank
2026-09-08 17:28:21 +02:00
co-authored by Claude Sonnet 5
parent 373fa6f78b
commit 7fbf6f1569
5 changed files with 579 additions and 7 deletions
+295
View File
@@ -133,3 +133,298 @@ table.dataTable {
border-color: var(--bs-primary); border-color: var(--bs-primary);
transform: translateY(-2px); transform: translateY(-2px);
} }
/* --- Storyline: chapter index ----------------------------------------- */
.storyline-chapter-list {
display: grid;
gap: 0.75rem;
max-width: 60rem;
}
.storyline-chapter-card {
display: flex;
align-items: flex-start;
gap: 1rem;
padding: 1rem 1.25rem;
border: 1px solid var(--bs-border-color);
border-radius: 0.5rem;
background: var(--bs-body-bg);
text-decoration: none;
color: inherit;
transition: border-color 0.12s ease, transform 0.12s ease;
}
.storyline-chapter-card:hover {
border-color: var(--bs-primary);
transform: translateY(-2px);
}
.storyline-chapter-num {
flex: 0 0 auto;
width: 2rem;
height: 2rem;
display: grid;
place-items: center;
border-radius: 50%;
background: var(--bs-tertiary-bg);
border: 1px solid var(--bs-border-color);
font-variant-numeric: tabular-nums;
font-weight: 600;
}
.storyline-chapter-body {
flex: 1 1 auto;
min-width: 0;
}
.storyline-chapter-title {
display: block;
font-size: 1.125rem;
font-weight: 600;
}
.storyline-chapter-summary {
display: block;
color: var(--bs-secondary-color);
font-size: 0.9375rem;
margin-top: 0.15rem;
}
.storyline-chapter-go {
align-self: center;
color: var(--bs-secondary-color);
font-size: 1.25rem;
}
/* --- Storyline: chapter layout + table of contents ------------------- */
.storyline-toc {
position: sticky;
top: 1.5rem;
font-size: 0.9375rem;
}
.storyline-toc-link {
display: flex;
gap: 0.5rem;
padding: 0.3rem 0.5rem;
border-radius: 0.375rem;
border-left: 2px solid transparent;
text-decoration: none;
color: var(--bs-secondary-color);
}
.storyline-toc-link:hover {
color: var(--bs-body-color);
background: var(--bs-tertiary-bg);
}
.storyline-toc-link.is-active {
color: var(--bs-body-color);
border-left-color: var(--bs-primary);
background: var(--bs-tertiary-bg);
font-weight: 600;
}
.storyline-toc-num {
font-variant-numeric: tabular-nums;
color: var(--bs-secondary-color);
}
/* --- Storyline: the document itself --------------------------------- */
.storyline-doc {
max-width: 46rem;
font-size: 1.05rem;
line-height: 1.7;
}
.storyline-doc-head {
margin-bottom: 2.5rem;
padding-bottom: 1.25rem;
border-bottom: 1px solid var(--bs-border-color);
}
.storyline-eyebrow {
text-transform: uppercase;
letter-spacing: 0.09em;
font-size: 0.8rem;
font-weight: 700;
color: var(--bs-primary);
}
.storyline-doc-head h1 {
margin: 0.35rem 0 0.5rem;
font-size: clamp(1.9rem, 4vw, 2.6rem);
line-height: 1.15;
}
.storyline-standfirst {
font-size: 1.15rem;
color: var(--bs-secondary-color);
font-style: italic;
margin: 0;
}
.storyline-doc p {
margin: 0 0 1.1rem;
}
.storyline-doc u {
text-underline-offset: 0.18em;
text-decoration-thickness: 1px;
}
.storyline-section {
display: flex;
align-items: baseline;
gap: 0.75rem;
margin: 2.75rem 0 1rem;
padding-top: 1.25rem;
border-top: 1px solid var(--bs-border-color);
font-size: 1.45rem;
line-height: 1.25;
}
.storyline-section span {
flex: 0 0 auto;
font-variant-numeric: tabular-nums;
font-size: 0.9rem;
font-weight: 700;
color: var(--bs-primary);
padding-top: 0.35rem;
}
.storyline-lead {
font-size: 1.15rem;
}
.storyline-lead::first-letter {
/* subtle emphasis on the opening line of a section */
font-weight: 600;
}
.storyline-turn {
font-size: 1.2rem;
font-weight: 600;
text-align: center;
margin: 1.75rem 0 !important;
}
/* Pull-quotes for in-world spoken lines */
.storyline-quote {
margin: 1.5rem 0;
padding: 0.6rem 0 0.6rem 1.25rem;
border-left: 3px solid var(--bs-primary);
font-size: 1.2rem;
font-style: italic;
color: var(--bs-body-color);
}
.storyline-quote::before { content: "\201C"; }
.storyline-quote::after { content: "\201D"; }
.storyline-quote--close {
border-left: 0;
text-align: center;
font-size: 1.3rem;
padding: 1.5rem 1rem;
margin-top: 2.5rem;
border-top: 1px solid var(--bs-border-color);
}
/* GM callouts */
.storyline-callout {
position: relative;
margin: 1.75rem 0;
padding: 1.1rem 1.25rem 1.1rem 1.25rem;
background: var(--bs-tertiary-bg);
border: 1px solid var(--bs-border-color);
border-left: 3px solid var(--bs-info, #6ea8fe);
border-radius: 0.4rem;
}
.storyline-callout > :last-child { margin-bottom: 0; }
.storyline-callout::before {
content: attr(data-label);
display: block;
text-transform: uppercase;
letter-spacing: 0.08em;
font-size: 0.72rem;
font-weight: 700;
color: var(--bs-secondary-color);
margin-bottom: 0.4rem;
}
.storyline-callout--warn {
border-left-color: var(--bs-warning, #ffc107);
}
/* The escalation ladder in the Final Crisis */
.storyline-ladder {
margin: 1.25rem 0;
padding-left: 0;
list-style: none;
counter-reset: rung;
}
.storyline-ladder li {
counter-increment: rung;
position: relative;
padding: 0.55rem 0.9rem 0.55rem 2.75rem;
margin-bottom: 0.4rem;
background: var(--bs-tertiary-bg);
border: 1px solid var(--bs-border-color);
border-radius: 0.375rem;
font-style: italic;
}
.storyline-ladder li::before {
content: counter(rung);
position: absolute;
left: 0.9rem;
font-style: normal;
font-weight: 700;
color: var(--bs-primary);
}
/* Quick-reference panels (numbers + cast) */
.storyline-ref {
display: grid;
gap: 1rem;
grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
margin-bottom: 2.5rem;
}
.storyline-ref-panel {
padding: 1.1rem 1.25rem;
background: var(--bs-tertiary-bg);
border: 1px solid var(--bs-border-color);
border-radius: 0.5rem;
font-size: 0.95rem;
line-height: 1.5;
}
.storyline-ref-panel h3 {
font-size: 0.78rem;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--bs-secondary-color);
margin: 0 0 0.75rem;
}
.storyline-ref-panel dl { margin: 0; }
.storyline-ref-panel dl > div {
display: flex;
gap: 0.6rem;
padding: 0.2rem 0;
}
.storyline-ref-panel dt {
flex: 0 0 6.5rem;
font-variant-numeric: tabular-nums;
color: var(--bs-body-color);
}
.storyline-ref-panel dd {
margin: 0;
color: var(--bs-secondary-color);
}
.storyline-ref-panel ul {
margin: 0;
padding-left: 1.1rem;
}
.storyline-ref-panel li { margin-bottom: 0.5rem; }
.storyline-ref-panel li:last-child { margin-bottom: 0; }
/* Chapter pager */
.storyline-pager {
display: flex;
justify-content: space-between;
gap: 1rem;
margin-top: 3rem;
padding-top: 1.25rem;
border-top: 1px solid var(--bs-border-color);
}
.storyline-pager-link {
display: flex;
flex-direction: column;
gap: 0.15rem;
text-decoration: none;
color: inherit;
padding: 0.5rem 0.75rem;
border: 1px solid var(--bs-border-color);
border-radius: 0.4rem;
max-width: 48%;
}
.storyline-pager-link:hover { border-color: var(--bs-primary); }
.storyline-pager-dir {
font-size: 0.8rem;
color: var(--bs-secondary-color);
}
.storyline-pager-title { font-weight: 600; }
+39 -2
View File
@@ -10,9 +10,46 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
#[IsGranted('IS_AUTHENTICATED_FULLY')] #[IsGranted('IS_AUTHENTICATED_FULLY')]
class StorylineController extends AbstractController class StorylineController extends AbstractController
{ {
#[Route('/storyline', name: 'app_storyline')] /**
* The storyline is a set of hand-written chapters. Each entry points at a
* Twig partial under templates/storyline/chapters/. Add a chapter by adding
* a row here and the matching template; order in this array is reading order.
*
* @var array<string, array{title: string, summary: string, template: string}>
*/
private const CHAPTERS = [
'overview' => [
'title' => 'Campaign Overview',
'summary' => 'The whole shape of the Brackenford campaign, from the sealing of Kyuss four centuries ago to the final crisis — the truth behind the blood, the red herring around Sir Aldren, and how it can resolve.',
'template' => 'storyline/chapters/overview.html.twig',
],
];
#[Route('/storyline', name: 'app_storyline', methods: ['GET'])]
public function index(): Response public function index(): Response
{ {
return $this->render('storyline/index.html.twig'); return $this->render('storyline/index.html.twig', [
'chapters' => self::CHAPTERS,
]);
}
#[Route('/storyline/{slug}', name: 'app_storyline_chapter', requirements: ['slug' => '[a-z0-9-]+'], methods: ['GET'])]
public function chapter(string $slug): Response
{
if (!isset(self::CHAPTERS[$slug])) {
throw $this->createNotFoundException('No such storyline chapter.');
}
$slugs = array_keys(self::CHAPTERS);
$pos = array_search($slug, $slugs, true);
return $this->render('storyline/chapter.html.twig', [
'chapters' => self::CHAPTERS,
'slug' => $slug,
'number' => $pos + 1,
'chapter' => self::CHAPTERS[$slug],
'prev' => $pos > 0 ? $slugs[$pos - 1] : null,
'next' => $pos < \count($slugs) - 1 ? $slugs[$pos + 1] : null,
]);
} }
} }
+51
View File
@@ -0,0 +1,51 @@
{% extends 'base.html.twig' %}
{% block title %}{{ chapter.title }} · Storyline · dmtools{% endblock %}
{% block body %}
<div class="row g-4 storyline-layout">
<nav class="col-lg-3 order-lg-2">
<div class="storyline-toc">
<a href="{{ path('app_storyline') }}" class="text-decoration-none small d-inline-block mb-2">&larr; All chapters</a>
<div class="text-uppercase small text-body-secondary fw-semibold mb-2" style="letter-spacing:.08em">Chapters</div>
<ol class="list-unstyled mb-0">
{% for s, c in chapters %}
<li>
<a href="{{ path('app_storyline_chapter', {slug: s}) }}"
class="storyline-toc-link{{ s == slug ? ' is-active' }}">
<span class="storyline-toc-num">{{ loop.index }}</span>{{ c.title }}
</a>
</li>
{% endfor %}
</ol>
</div>
</nav>
<div class="col-lg-9 order-lg-1">
<article class="storyline-doc">
<header class="storyline-doc-head">
<div class="storyline-eyebrow">Storyline &middot; Chapter {{ number }}</div>
<h1>{{ chapter.title }}</h1>
<p class="storyline-standfirst">{{ chapter.summary }}</p>
</header>
{{ include(chapter.template) }}
</article>
<nav class="storyline-pager">
{% if prev %}
<a href="{{ path('app_storyline_chapter', {slug: prev}) }}" class="storyline-pager-link">
<span class="storyline-pager-dir">&larr; Previous</span>
<span class="storyline-pager-title">{{ chapters[prev].title }}</span>
</a>
{% else %}<span></span>{% endif %}
{% if next %}
<a href="{{ path('app_storyline_chapter', {slug: next}) }}" class="storyline-pager-link text-lg-end">
<span class="storyline-pager-dir">Next &rarr;</span>
<span class="storyline-pager-title">{{ chapters[next].title }}</span>
</a>
{% else %}<span></span>{% endif %}
</nav>
</div>
</div>
{% endblock %}
@@ -0,0 +1,169 @@
{# Campaign Overview — hand-formatted from the campaign bible text. #}
<section class="storyline-ref">
<div class="storyline-ref-panel">
<h3>By the numbers</h3>
<dl>
<div><dt>~400 years</dt><dd>since the five heroes sealed Kyuss</dd></div>
<div><dt>~175</dt><dd>villagers in Brackenford</dd></div>
<div><dt>~133</dt><dd>eligible blood donors</dd></div>
<div><dt>~15 litres</dt><dd>of blood collected every month</dd></div>
<div><dt>~2 litres</dt><dd>per month is all Aldren needs for himself</dd></div>
<div><dt>~1 hour</dt><dd>village to castle (the party travels in for ~2)</dd></div>
<div><dt>Age 15</dt><dd>when village-born children are told the secret</dd></div>
</dl>
</div>
<div class="storyline-ref-panel">
<h3>The cast</h3>
<ul>
<li><strong>Sir Aldren</strong> — one of the original five heroes; cursed with vampirism by Kyuss; for four centuries the prison's unseen Warden.</li>
<li><strong>Kyuss</strong> — the ancient evil (or a fragment of it) sealed beneath the castle, now leaking out as the seal fails.</li>
<li><strong>Eamon Vale</strong> — 41, a Brackenford farmer; inherits; meets Aldren; misunderstands him; is hidden away by the council.</li>
<li><strong>Garrick Voss</strong> — 61, a village elder; not evil, but afraid; the party's fiercest opposition.</li>
<li><strong>Bastian Cooper</strong> — drives the blood cart to the castle each month.</li>
<li><strong>The halfling family</strong> — the player characters: hired to deliver the inheritance and come back with Eamon's signed, magically authenticated receipt.</li>
</ul>
</div>
</section>
<h2 class="storyline-section"><span>01</span> The Truth, Four Hundred Years Ago</h2>
<p class="storyline-lead">Roughly four centuries ago, something connected to <strong>Kyuss</strong> began spreading through the region that now surrounds Brackenford.</p>
<p>Whether it was Kyuss himself, an aspect of him, or a fragment of his power can stay deliberately uncertain. What matters is that it <strong>could not simply be killed</strong>. Its influence corrupted living creatures, animated the dead, and gradually transformed the land.</p>
<p><strong>Five adventurers</strong> confronted it. Among them was <strong>Sir Aldren</strong>, then a mortal warrior and accomplished fighter.</p>
<p>They eventually discovered that destroying the entity was impossible. Instead they devised a prison: an ancient magical seal capable of containing the fragment and keeping its influence from the world. They succeeded &mdash; but not without cost.</p>
<p>During the final confrontation, <strong>Kyuss cursed Aldren with vampirism</strong>. It was meant as a last act of cruelty: one of the heroes who had fought undeath would himself become an undead monster.</p>
<p>Kyuss made one critical mistake. <u>Aldren did not leave.</u> Rather than surrender to his curse, he became the guardian of the very prison he had helped create. The other four heroes eventually died. <strong>Aldren remained. For four hundred years.</strong></p>
<h2 class="storyline-section"><span>02</span> The Blood</h2>
<p>The prison was never completely self-sustaining. Maintaining the seal requires <strong>life energy</strong>, and blood is an effective conduit for it.</p>
<p>Aldren also requires blood to remain sane &mdash; but the amount he personally consumes is <strong>surprisingly small</strong>, roughly <strong>two litres per month</strong>. The remainder goes toward maintaining the prison.</p>
<p>Over the centuries the details were lost. The people of Brackenford remember only the simplified version:</p>
<blockquote class="storyline-quote">There is a vampire in the castle. Give him blood, and he leaves Brackenford alone.</blockquote>
<p><strong>Nobody alive remembers that Aldren is protecting them.</strong> Nobody remembers Kyuss. Nobody remembers what the blood actually does. Even the village council doesn't know the full truth. They aren't maintaining a sinister conspiracy &mdash; they're maintaining <strong>a tradition they are terrified to stop</strong>.</p>
<h2 class="storyline-section"><span>03</span> Modern Brackenford</h2>
<p class="storyline-lead">Brackenford is an isolated but prosperous, largely self-sufficient village in the hills, with roughly <strong>175 inhabitants</strong>.</p>
<p>It farms its own food, raises livestock, makes clothing, and keeps the craftsmen, hunters, woodcutters, mill, temple, tavern and inn a village needs. It isn't completely cut off: several other villages lie about a day's journey apart, and apprentices move between settlements &mdash; bringing new skills, marriages and &ldquo;new blood.&rdquo;</p>
<p>Outsiders who settle permanently eventually undergo a ceremony in which they are told the village's great secret. Children born in Brackenford learn it during a ceremony in the year they turn <strong>fifteen</strong>. The secret is simple: <strong>Sir Aldren is a vampire, and once a month Brackenford sends him blood.</strong></p>
<p>There are currently around <strong>133 eligible donors</strong>. About <strong>15 litres</strong> of blood are collected each month, spread across enough villagers that individual donors get substantial recovery time. The villagers believe this is <strong>tribute</strong>. The blood is loaded onto a specially maintained cart and driven by <strong>Bastian Cooper</strong> to Aldren's castle, roughly an hour away. For generations it has worked. <strong>Nobody asks why.</strong></p>
<h2 class="storyline-section"><span>04</span> But the System Is Failing</h2>
<p>Aldren has known for some time that something is wrong. The seal is deteriorating. At first he compensated himself. Then maintaining it began requiring more blood. Then more. The normal fifteen litres eventually became <strong>insufficient</strong>.</p>
<p>Unlike the previous centuries, the deterioration has now reached a <strong>tipping point</strong>, and the failure is <strong>accelerating</strong>. Aldren is exhausted. He has been doing this for four hundred years and has lost everyone he once knew. The purpose of many parts of the original mechanism is becoming difficult even for him to remember, and parts of the prison have physically decayed.</p>
<p>And Aldren himself is <strong>starving</strong>. Of the blood sent each month, he takes only what he needs to retain control of himself. He refuses to take more simply to make himself stronger when that blood is desperately needed by the seal.</p>
<aside class="storyline-callout" data-label="Ticking clock">
He knows something the people of Brackenford don't: <strong>the prison will fail soon.</strong> Not in another century. Not in ten years. Possibly <strong>within weeks</strong>.
</aside>
<h2 class="storyline-section"><span>05</span> The Heir</h2>
<p>Meanwhile, somewhere completely unrelated to this ancient problem, someone dies. The deceased leaves an inheritance to <strong>Eamon Vale</strong>, a 41-year-old farmer living in Brackenford.</p>
<p>A group of halflings &mdash; a family trying to earn enough money for their farm &mdash; accepts what sounds like an unusually lucrative but very easy job: <strong>deliver the inheritance to Eamon Vale.</strong> They receive half their payment in advance. To collect the rest they must return with a <strong>magically authenticated receipt signed by Eamon himself</strong>. No Eamon, no signature. No signature, no money.</p>
<aside class="storyline-callout" data-label="Why the players stay">
They aren't travelling to Brackenford to save the world. <strong>They're trying to get paid.</strong>
</aside>
<h2 class="storyline-section"><span>06</span> The Night Before Their Arrival</h2>
<p>Shortly before the characters reach Brackenford, Eamon is outside the village in the early evening. He encounters <strong>Sir Aldren</strong>, who is desperate enough to break centuries of distance between himself and the villagers.</p>
<p>Exactly what Aldren says should be carefully chosen. Something along the lines of:</p>
<blockquote class="storyline-quote">Tell them the blood is no longer enough.</blockquote>
<p><strong>Aldren means:</strong> the seal is failing. <strong>Eamon hears:</strong> the vampire wants more.</p>
<p>He runs back to Brackenford terrified, telling people that Aldren approached him, that the vampire says the blood isn't enough, and that he wants more. Panic begins to spread. The council intervenes: Eamon is taken somewhere secure, supposedly for his own protection and to let him calm down, because they don't want rumours running through the village before they understand what happened.</p>
<p>Then five complete outsiders arrive and ask:</p>
<blockquote class="storyline-quote">Where can we find Eamon Vale?</blockquote>
<h2 class="storyline-section"><span>07</span> The Beginning of the Mystery</h2>
<p>The characters reach Brackenford after roughly two hours' travel. Eamon is nowhere to be found. At the tavern or inn they ask after him, and the reaction is strange &mdash; people exchange glances. Someone tells them:</p>
<blockquote class="storyline-quote">We'll take the inheritance for him.</blockquote>
<p>Unfortunately that isn't possible: they specifically need Eamon's magically authenticated signature. At first nobody wants to explain where he is.</p>
<p>Now the players have exactly the incentive we wanted. They don't investigate because a mysterious village sounds interesting. <strong>Someone in this village is preventing them from finishing their job and getting their money.</strong></p>
<h2 class="storyline-section"><span>08</span> What the Players Begin to Discover</h2>
<p>Their search for Eamon gradually exposes cracks in Brackenford's pleasant exterior. People become evasive when the castle is mentioned. Certain subjects immediately end conversations. The council insists Eamon is safe. The villagers have peculiar customs surrounding blood. Some are frightened of outsiders asking too many questions.</p>
<p>Eventually the party learns about the <strong>blood cart</strong>. Once every month, blood leaves Brackenford, travels to the castle, and in that castle lives <strong>Sir Aldren &mdash; a vampire</strong>.</p>
<p>Suddenly everything makes sense. Eamon encountered the vampire. The vampire demanded more blood. The council silenced Eamon. The village secretly feeds the vampire. The elders don't want outsiders investigating. There is a monster in a castle overlooking Brackenford.</p>
<p class="storyline-turn">The players have solved the mystery. <u>Except they haven't.</u></p>
<h2 class="storyline-section"><span>09</span> Garrick Voss</h2>
<p><strong>Garrick Voss</strong>, a 61-year-old village elder, becomes one of the strongest sources of resistance. Garrick isn't evil. He is <strong>afraid</strong>. His family has survived in Brackenford because generations before him followed the rules: blood goes into the cart, the cart goes to Aldren, Aldren stays away, nobody dies.</p>
<p>As far as Garrick is concerned, that is an extraordinarily successful arrangement &mdash; and then five outsiders arrive and immediately start questioning something that has kept his family alive for centuries. Eventually his frustration can produce the line:</p>
<blockquote class="storyline-quote">You are outside blood.</blockquote>
<p>They have no right, in his eyes, to risk Brackenford's children because they're curious. And if they insist on interfering with the arrangement:</p>
<blockquote class="storyline-quote">Then perhaps you can pay with your blood.</blockquote>
<p>This strongly reinforces the apparent truth: <strong>the elders are protecting the vampire.</strong></p>
<h2 class="storyline-section"><span>10</span> Finding Eamon</h2>
<p>Importantly, the characters should <strong>not</strong> find Eamon immediately. By the time they reach him, they should already know enough about the blood cart that his story matters.</p>
<p>Eamon tells them what happened. He was outside. He encountered Aldren. And Aldren told him: <strong>the blood is no longer enough.</strong></p>
<aside class="storyline-callout" data-label="First ticking clock">
This becomes the campaign's first major deadline: the next blood cart is coming, and the vampire is apparently expecting more.
</aside>
<h2 class="storyline-section"><span>11</span> Sir Aldren, the Monster in the Castle</h2>
<p>Everything should push the players toward one obvious conclusion: <strong>Aldren is the campaign's villain.</strong></p>
<p>He is a four-hundred-year-old vampire. Villagers send him blood. He lives alone in an old castle. He recently approached a villager and demanded more. The council is terrified of angering him. Strange things are beginning to happen around Brackenford. And the worse the seal becomes, the more undead phenomena appear &mdash; which, from the players' perspective, seems to <strong>prove that Aldren is becoming more powerful.</strong></p>
<aside class="storyline-callout" data-label="The central red herring">
The players are correctly interpreting almost every individual clue. They are simply drawing <strong>the wrong connection</strong> between them.
</aside>
<h2 class="storyline-section"><span>12</span> The World Begins to Turn Against Them</h2>
<p>The manifestations start small. Animals behave strangely. Plants rot unexpectedly. People hear things at night. Dead animals don't stay where they were buried. Worms &mdash; or similar imagery associated with <strong>Kyuss</strong> &mdash; begin appearing.</p>
<p>Then things escalate. Undead appear. The countryside becomes increasingly hostile. Old places around Brackenford begin reacting to something. Ancient symbols are uncovered. Parts of the forgotten history of the region resurface.</p>
<p>The party learns that roughly four hundred years ago, <strong>five heroes fought some terrible evil here</strong>. This is a local legend in Brackenford; a village or two away it's merely an old story; further away almost nobody has heard of it, and much of the tale has been distorted.</p>
<p>Eventually the party discovers something deeply inconvenient: <strong>Sir Aldren was one of the five heroes.</strong></p>
<h2 class="storyline-section"><span>13</span> The Five and the Five</h2>
<p>There is a deliberate parallel. Four hundred years ago, five adventurers arrived to confront the evil. Now, five adventurers stand in Brackenford.</p>
<aside class="storyline-callout" data-label="Design intent">
This shouldn't become a prophecy or reincarnation story. The modern party isn't destined to repeat history; the parallel is <strong>thematic</strong>. But Aldren sees it, and it can affect him profoundly. For four centuries everyone he fought beside has been dead &mdash; and then five people walk into his castle together. Perhaps, for just a moment, Aldren sees his old companions standing there.
</aside>
<h2 class="storyline-section"><span>14</span> Meeting Aldren</h2>
<p>The eventual meeting with Aldren should <strong>overturn the campaign</strong>. The party expects a vampire lord. Instead they find <strong>a tired soldier</strong> &mdash; still dangerous, still frightening, still unmistakably a vampire, but exhausted.</p>
<p>Aldren isn't surrounded by victims. There is no court of vampire spawn. There are no dungeons filled with villagers. There is a man who has spent four centuries guarding something. Perhaps they find him physically <strong>beside part of the seal</strong>.</p>
<p>And when they confront him about demanding more blood, they finally learn the truth:</p>
<blockquote class="storyline-quote">You think the blood is for me?</blockquote>
<p>Only a fraction is. The rest keeps <strong>something else</strong> imprisoned.</p>
<h2 class="storyline-section"><span>15</span> Kyuss</h2>
<p>Now the campaign changes. The question is no longer <em>how do we kill Aldren?</em> It becomes <strong>what has Aldren been keeping underneath this place for four hundred years?</strong></p>
<p>The ancient evil associated with <strong>Kyuss</strong> has been contained beneath or around the castle. Aldren isn't its master &mdash; he is its <strong>jailer</strong>. His vampirism isn't evidence that he serves the ancient evil; it is <strong>the scar Kyuss left on him</strong> when Aldren helped imprison it.</p>
<p>And now the prison is failing. The strange events around Brackenford aren't Aldren's influence spreading. <u>They're Kyuss leaking out.</u></p>
<h2 class="storyline-section"><span>16</span> The Dangerous Possibility</h2>
<aside class="storyline-callout storyline-callout--warn" data-label="Warning">
<p>The players genuinely <strong>can</strong> attack Aldren before discovering the truth. If they defeat or severely weaken him too early, they haven't solved the problem &mdash; they've just removed one of the things keeping the prison stable. The prison opens further and the campaign suddenly becomes substantially worse.</p>
<p>That makes the twist <strong>meaningful rather than cosmetic</strong>. The players weren't merely mistaken about Aldren; acting on that mistake has consequences. But it shouldn't automatically end the campaign &mdash; it simply forces them to solve a much more desperate version of the same crisis.</p>
</aside>
<h2 class="storyline-section"><span>17</span> The Blood Cart</h2>
<p>Eventually the monthly collection occurs. This should be the <strong>only</strong> actual blood-cart departure the characters witness during the campaign. By then the cart isn't abstract anymore: they know these people. They've eaten with them. They've spoken to their children. They know <strong>Bastian Cooper</strong>. They know the families whose blood is being collected.</p>
<p>Around <strong>15 litres</strong> are prepared &mdash; and now the characters know something most of those villagers don't: <strong>it isn't enough.</strong></p>
<p>The village has around <strong>133 eligible donors</strong>. There is physically enough blood available to <strong>temporarily reinforce the seal</strong>. But convincing Brackenford to provide dramatically more than the traditional amount means asking an entire community to overturn <strong>four centuries of fear</strong>.</p>
<p>The villagers believe additional blood means <strong>feeding the monster</strong>. The characters know it means <strong>buying time</strong>. And <strong>Garrick Voss</strong> &mdash; who earlier told them to pay with their own &ldquo;outside blood&rdquo; &mdash; now has to confront the possibility that the tradition he fiercely protected was based on a misunderstanding.</p>
<h2 class="storyline-section"><span>18</span> Solving the Problem</h2>
<p>More blood cannot be the permanent solution. The extra blood should only stabilise the prison <strong>temporarily</strong>. It buys the characters enough time to actually repair what is broken.</p>
<p>The final portion of the campaign therefore becomes about <strong>reconstructing knowledge lost over four centuries</strong>. The five original adventurers knew how the prison worked. That knowledge is now fragmented: some is in Aldren's memory, some survives in local legends, and some may exist in ruins, inscriptions, old family records or forgotten structures around Brackenford.</p>
<aside class="storyline-callout" data-label="The puzzle">
This is where the English-language puzzle can become important. Rather than a random dungeon puzzle, it can be part of the original five heroes' mechanism &mdash; a safeguard designed so that someone who came after them could restore the prison.
</aside>
<p>The players must understand what their predecessors did before they can repair it. <strong>The campaign's investigation finally becomes its solution. Everything they've learned matters.</strong></p>
<h2 class="storyline-section"><span>19</span> The Final Crisis</h2>
<p>As the seal approaches failure, Kyuss's influence becomes undeniable. The campaign moves through four stages:</p>
<ol class="storyline-ladder">
<li>&ldquo;Something is strange about this village.&rdquo;</li>
<li>&ldquo;There is a vampire in that castle.&rdquo;</li>
<li>&ldquo;The vampire isn't the monster.&rdquo;</li>
<li>&ldquo;The world itself is turning against us.&rdquo;</li>
</ol>
<p>The characters have only a short period in which to act. They need <strong>blood</strong> to stabilise the mechanism. They need <strong>Aldren's knowledge</strong>. They need <strong>information left behind by the original five</strong>. They need the <strong>cooperation of Brackenford</strong>. And they need to <strong>survive</strong> whatever manifestations of Kyuss emerge as the prison begins opening.</p>
<p>Nobody else can realistically solve it in time. Not because they're chosen. <strong>Because they're here.</strong></p>
<h2 class="storyline-section"><span>20</span> The Ending</h2>
<p>If they succeed, <strong>Kyuss is contained again. Brackenford survives.</strong> But things cannot simply return to normal.</p>
<p>The villagers now know &mdash; or at least some of them know &mdash; that their ancestors misunderstood the blood ritual. Their supposed monster was their protector. Their council maintained a lie without even knowing it was a lie. Aldren has spent four centuries protecting people who feared and hated him. And <strong>the prison still exists.</strong></p>
<p>The characters haven't destroyed Kyuss. <strong>They've bought Brackenford another future.</strong></p>
<p>Aldren's fate can depend on the choices made during the campaign. He might remain the Warden. He might finally be freed from his duty at enormous cost. He might die ensuring the repaired prison closes. This can stay undecided until the mechanics of the seal and the five original heroes are finalised. But the village is safe. For now.</p>
<p>The halflings can finally get Eamon's signature. They can return with proof that the inheritance was delivered, and collect the other half of their payment. They leave Brackenford considerably less innocent than when they entered it.</p>
<blockquote class="storyline-quote storyline-quote--close">We should have done more for those people. But right now, they're safe.</blockquote>
+25 -5
View File
@@ -3,9 +3,29 @@
{% block title %}Storyline · dmtools{% endblock %} {% block title %}Storyline · dmtools{% endblock %}
{% block body %} {% block body %}
{{ include('_partials/page_placeholder.html.twig', { <div class="storyline-index">
title: 'Storyline', <header class="mb-4">
icon: '📜', <div class="text-uppercase small text-body-secondary fw-semibold" style="letter-spacing:.08em">Storyline</div>
blurb: 'The campaign storyline will live here. Shape still to be decided — session log, plot threads, or a wiki-style document.', <h1 class="display-6 mb-2">Brackenford</h1>
}) }} <p class="text-body-secondary mb-0" style="max-width:60ch">
The campaign bible, split into chapters. Start with the overview for the whole
arc; later chapters will cover sessions, locations and the people of the village.
</p>
</header>
<ol class="storyline-chapter-list list-unstyled">
{% for slug, chapter in chapters %}
<li>
<a href="{{ path('app_storyline_chapter', {slug: slug}) }}" class="storyline-chapter-card">
<span class="storyline-chapter-num">{{ loop.index }}</span>
<span class="storyline-chapter-body">
<span class="storyline-chapter-title">{{ chapter.title }}</span>
<span class="storyline-chapter-summary">{{ chapter.summary }}</span>
</span>
<span class="storyline-chapter-go" aria-hidden="true">&rarr;</span>
</a>
</li>
{% endfor %}
</ol>
</div>
{% endblock %} {% endblock %}