QuestKeeper Product Page + Documentation Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Add QuestKeeper as a new product on the Anchorlight site: a registry entry, a full custom landing page, a 9-page documentation set, and nav/footer wiring — following the existing Ascendra/ConsentPVP pattern for Minecraft plugins.
Architecture: Docusaurus classic preset site (ald-website). Products live in a single src/data/products.ts registry consumed by the homepage/catalogue and by each product's own landing page under src/pages/products/<slug>.tsx. Docs are plain Markdown under docs/products/<slug>/ with an autogenerated Docusaurus sidebar registered per-product in sidebars.ts (single unified docs plugin instance — no new plugin config needed).
Tech Stack: TypeScript, React 19, Docusaurus 3.10 (classic preset), CSS Modules.
Global Constraints
- Source of truth for all copy:
C:\Users\Ben\Documents\GitHub\QuestKeeper\README.mdandC:\Users\Ben\Documents\GitHub\QuestKeeper\src\main\resources\plugin.yml(plugin version0.1.0-SNAPSHOT). Do not invent functionality beyond what those files state. - Requirements: Paper
1.21.4+, Citizens2.x, Java21+. Optional soft-dependency: ConsentPvP (ConsentPVPinplugin.yml). slug: 'questkeeper',category: 'Minecraft Plugin',status: 'in-development',color: '#d97706'.- No logo asset exists yet — do not set
logoSrc/logoWidth/logoHeight, and the landing page must render without a logo image. - Fully public: do not set
noindex: true, and do not add the page to any sitemap-ignore pattern. showInNav: true,docsUrl: '/docs/products/questkeeper'.- Repo root for this work is
c:\Users\Ben\Documents\GitHub\ald-website(a different repo from the Java plugin source).
Task 1: Product registry entry
Files:
- Modify:
src/data/products.ts:161(insert a new entry — alphabetically betweenrallypointandtutorialbuddy, matching the existing alphabetical ordering of theproductsarray)
Interfaces:
-
Consumes: existing
Producttype andproductLogohelper already defined in this file (no changes to the type). -
Produces:
getProduct('questkeeper')— used by Task 3 (landing page). -
Step 1: Add the QuestKeeper entry to the
productsarray
Open src/data/products.ts and insert this object into the products array, immediately after the rallypoint entry (which ends at line 160 with },) and before the tutorialbuddy entry:
{
slug: 'questkeeper',
name: 'QuestKeeper',
tagline: 'A new daily quest for your server, every day.',
description:
'A Paper Minecraft plugin that generates a new daily quest for your server every day, delivered through a Citizens NPC. Quests are automatically generated and validated across many types — delivering items, herding mobs, exploring biomes, discovering structures, fighting mobs, crafting, trading with villagers, and biome-specific gathering — with optional timed BossBar challenges. Players earn points and build streaks with no manual quest writing required.',
category: 'Minecraft Plugin',
status: 'in-development',
color: '#d97706',
features: [
'Automatic daily quests across 8 quest types',
'Delivered and turned in through a Citizens NPC',
'Points, streaks, and a spendable Quest Shop',
'Optional timed BossBar challenge quests',
],
docsUrl: '/docs/products/questkeeper',
showInNav: true,
},
- Step 2: Verify the file still type-checks
Run: npm run typecheck
Expected: exits with no errors (no output beyond the tsc invocation, exit code 0).
- Step 3: Commit
git add src/data/products.ts
git commit -m "Add QuestKeeper to the product registry"
Task 2: Landing page stylesheet
Files:
- Create:
src/pages/products/questkeeper.module.css(copied fromsrc/pages/products/consentpvp.module.css, then recolored)
Interfaces:
-
Consumes: nothing (pure CSS module).
-
Produces: CSS class names identical to
consentpvp.module.css's exports (e.g..hero,.heroLogo,.badges,.categoryBadge,.statusBadge,.heroTitle,.heroTagline,.heroLede,.heroActions,.valueSection,.eyebrow,.sectionTitle,.sectionSubtitle,.featureSection,.featureCard,.featureIcon,.featureTitle,.featureDesc,.stepsSection,.stepsGrid,.stepCard,.stepNumber,.stepTitle,.stepDesc,.detailSection,.detailText,.integrationList,.specCard,.specTitle,.specList,.specRow,.ctaSection,.ctaActions,.breadcrumbBar) — Task 3 relies on these exact names. -
Step 1: Copy the ConsentPVP stylesheet as a starting point
cp src/pages/products/consentpvp.module.css src/pages/products/questkeeper.module.css
- Step 2: Recolor the fallback
--product-colorvalues and swap the decorative bullet icon
sed -i "s/#22c55e/#d97706/g; s/#22C55E/#D97706/g; s/'⚔'/'📜'/g" src/pages/products/questkeeper.module.css
- Step 3: Verify no ConsentPVP-specific colors remain
Run: grep -in "22c55e\|22C55E" src/pages/products/questkeeper.module.css
Expected: no output (no matches).
- Step 4: Commit
git add src/pages/products/questkeeper.module.css
git commit -m "Add QuestKeeper landing page stylesheet"
Task 3: Landing page component
Files:
- Create:
src/pages/products/questkeeper.tsx
Interfaces:
-
Consumes:
getProduct('questkeeper')from Task 1 (src/data/products.ts),STATUS_LABEL/STATUS_COLOR_VAR(already exported bysrc/data/products.ts), CSS classes from Task 2 (questkeeper.module.css), and shared componentsLayout(@theme/Layout),Heading(@theme/Heading),Breadcrumbs(@site/src/components/Breadcrumbs),OffsetSplit(@site/src/components/layout/OffsetSplit),StaggeredGrid(@site/src/components/layout/StaggeredGrid) — all already used identically bysrc/pages/products/consentpvp.tsx. -
Produces: the
/products/questkeeperroute (Docusaurus file-based routing — no manual route registration needed). -
Step 1: Create the landing page
Create src/pages/products/questkeeper.tsx:
import type {ReactNode, CSSProperties} from 'react';
import clsx from 'clsx';
import Link from '@docusaurus/Link';
import Layout from '@theme/Layout';
import Heading from '@theme/Heading';
import styles from './questkeeper.module.css';
import {getProduct, STATUS_LABEL, STATUS_COLOR_VAR} from '@site/src/data/products';
import Breadcrumbs from '@site/src/components/Breadcrumbs';
import OffsetSplit from '@site/src/components/layout/OffsetSplit';
import StaggeredGrid from '@site/src/components/layout/StaggeredGrid';
const product = getProduct('questkeeper')!;
type Highlight = {icon: string; title: string; description: string};
const highlights: Highlight[] = [
{
icon: '📜',
title: 'One Daily Quest, Server-Wide',
description:
'A single active quest per day, shared by the whole server. Every player can complete it once, delivered through a Citizens NPC.',
},
{
icon: '🧩',
title: '8 Quest Types',
description:
'Item delivery, mob delivery, exploration, structure discovery, combat, crafting, villager trading, and biome collection — all validated automatically.',
},
{
icon: '⏱️',
title: 'Timed BossBar Challenges',
description:
'Eligible quests can gain a countdown timer shown as a BossBar. Finish in time or the quest fails for the day.',
},
{
icon: '🔥',
title: 'Points & Streaks',
description:
'Completing a quest awards a Quest Point and builds a daily streak. Miss a day and the streak resets to one.',
},
{
icon: '🛍️',
title: 'Quest Shop',
description:
'Spend Quest Points on Teleport Scrolls, Streak Shields, timed-quest extensions, chat colors, and completion effects.',
},
{
icon: '🎯',
title: 'No Manual Quest Writing',
description:
'Quests are generated and validated automatically from curated internal pools — no config files to maintain.',
},
];
type Step = {number: string; title: string; description: string};
const steps: Step[] = [
{
number: '1',
title: 'Install the plugin',
description:
'Drop the QuestKeeper jar into plugins/ alongside Citizens, which QuestKeeper depends on.',
},
{
number: '2',
title: 'Create the quest NPC',
description:
'Run /npc create QuestKeeper with Citizens, then note its ID from /npc list.',
},
{
number: '3',
title: 'Point the config at it',
description:
'Set quest-npc-id in config.yml, then reload or run /qk forcerefresh.',
},
{
number: '4',
title: 'Players start questing',
description:
'Right-clicking the NPC shows today’s quest — completion delivers a Quest Point and builds a streak.',
},
];
type Spec = {label: string; value: string};
const specs: Spec[] = [
{label: 'Platform', value: 'Paper'},
{label: 'Minecraft API', value: '1.21.4+'},
{label: 'Dependency', value: 'Citizens 2.x'},
{label: 'Java', value: '21+'},
];
export default function QuestKeeper(): ReactNode {
const colorVars = {'--product-color': product.color} as CSSProperties;
return (
<Layout
title="QuestKeeper"
description="QuestKeeper is a Paper Minecraft plugin that generates a new daily quest for your server every day, delivered through a Citizens NPC.">
<div className={styles.breadcrumbBar}>
<div className="container">
<Breadcrumbs
items={[
{label: 'Home', href: '/'},
{label: 'Products', href: '/products'},
{label: 'QuestKeeper', href: '/products/questkeeper'},
]}
/>
</div>
</div>
{/* ── Hero ───────────────────────────────────────────────────────── */}
<header className={styles.hero} style={colorVars}>
<div className="container">
<div className={styles.badges}>
<span className={styles.categoryBadge}>{product.category}</span>
<span
className={styles.statusBadge}
style={{background: STATUS_COLOR_VAR[product.status]}}>
{STATUS_LABEL[product.status]}
</span>
</div>
<Heading as="h1" className={styles.heroTitle}>
QuestKeeper
</Heading>
<p className={styles.heroTagline}>
A new daily quest for your server, every day.
</p>
<p className={styles.heroLede}>
QuestKeeper generates a fresh daily quest for your whole server,
delivered through a Citizens NPC. Quests span item delivery, mob
herding, exploration, combat, crafting, and more — all generated
and validated automatically, with no manual quest writing
required.
</p>
<div className={styles.heroActions}>
<Link
className="button button--secondary button--lg"
to={product.docsUrl}>
View Documentation
</Link>
<Link
className="button button--outline button--secondary button--lg"
to="/products">
← All Products
</Link>
</div>
</div>
</header>
<main>
{/* ── Value proposition ────────────────────────────────────────── */}
<section className={styles.valueSection}>
<div className="container text--center">
<span className={styles.eyebrow}>Why QuestKeeper</span>
<Heading as="h2" className={styles.sectionTitle}>
A reason to log in every day
</Heading>
<p className={styles.sectionSubtitle}>
One shared quest a day gives your server a common goal without
any setup. QuestKeeper handles generation, validation, and
rewards — you just place the NPC.
</p>
</div>
</section>
{/* ── Feature grid ─────────────────────────────────────────────── */}
<section className={styles.featureSection} style={colorVars}>
<div className="container">
<StaggeredGrid columns={3}>
{highlights.map((h) => (
<div key={h.title} className={styles.featureCard}>
<div className={styles.featureIcon}>{h.icon}</div>
<Heading as="h3" className={styles.featureTitle}>
{h.title}
</Heading>
<p className={styles.featureDesc}>{h.description}</p>
</div>
))}
</StaggeredGrid>
</div>
</section>
{/* ── How it works ─────────────────────────────────────────────── */}
<section className={styles.stepsSection}>
<div className="container">
<div className="text--center">
<span className={styles.eyebrow}>How it works</span>
<Heading as="h2" className={styles.sectionTitle}>
Live in four steps
</Heading>
</div>
<div className={styles.stepsGrid}>
{steps.map((s) => (
<div key={s.number} className={styles.stepCard} style={colorVars}>
<span className={styles.stepNumber}>{s.number}</span>
<Heading as="h3" className={styles.stepTitle}>
{s.title}
</Heading>
<p className={styles.stepDesc}>{s.description}</p>
</div>
))}
</div>
</div>
</section>
{/* ── Integrations + specs ─────────────────────────────────────── */}
<section className={styles.detailSection}>
<div className="container">
<OffsetSplit
leftWidth={7}
left={
<>
<span className={styles.eyebrow}>Plays well with others</span>
<Heading as="h2" className={styles.sectionTitle}>
Optional integrations
</Heading>
<p className={styles.detailText}>
QuestKeeper works fully on its own, and adjusts its
behavior when this soft dependency is present.
</p>
<ul className={styles.integrationList}>
<li>
<strong>ConsentPvP</strong> — when installed, the
Teleport Scroll system only lets a player teleport to
someone who has consented. Without it, teleport consent
checks are skipped.
</li>
</ul>
</>
}
right={
<div className={styles.specCard} style={colorVars}>
<Heading as="h3" className={styles.specTitle}>
At a glance
</Heading>
<dl className={styles.specList}>
{specs.map((s) => (
<div key={s.label} className={styles.specRow}>
<dt>{s.label}</dt>
<dd>{s.value}</dd>
</div>
))}
</dl>
</div>
}
/>
</div>
</section>
{/* ── CTA ──────────────────────────────────────────────────────── */}
<section className={clsx(styles.ctaSection, 'al-angled-top')} style={colorVars}>
<div className="container text--center">
<Heading as="h2">Ready to give your server a daily quest?</Heading>
<p>
Dive into the documentation for installation, commands,
configuration, and the full quest-type reference.
</p>
<div className={styles.ctaActions}>
<Link
className="button button--accent button--lg"
to={product.docsUrl}>
Read the Docs
</Link>
<Link
className="button button--outline button--secondary button--lg"
to="/products">
Explore More Products
</Link>
</div>
</div>
</section>
</main>
</Layout>
);
}
- Step 2: Verify it type-checks
Run: npm run typecheck
Expected: exits with no errors.
- Step 3: Start the dev server and visually confirm the page renders
Run: npm run start (in the background, or in a separate terminal), then open http://localhost:3000/products/questkeeper.
Expected: page loads with no console errors, showing the hero, six feature cards, four steps, the ConsentPvP integration note, and the spec list. Stop the dev server after checking.
- Step 4: Commit
git add src/pages/products/questkeeper.tsx
git commit -m "Add QuestKeeper landing page"
Task 4: Sidebar and footer wiring
Files:
- Modify:
sidebars.ts:18-24(insert a newquestkeepersidebar entry, alphabetically afterconsentpvpand beforedevoteme) - Modify:
docusaurus.config.ts(footer'Products'column, currently at line 147-154)
Interfaces:
-
Consumes: nothing new —
sidebars.ts'sSidebarsConfigtype anddocusaurus.config.ts's existing footer array shape are unchanged. -
Produces: the
/docs/products/questkeeper/*doc pages (Task 5–7) will resolve into thequestkeepersidebar defined here. -
Step 1: Add the QuestKeeper sidebar to
sidebars.ts
In sidebars.ts, insert this block immediately after the consentpvp entry (which ends at line 24 with ],) and before the devoteme entry:
questkeeper: [
{
type: 'autogenerated',
dirName: 'products/questkeeper',
},
],
- Step 2: Add the footer link in
docusaurus.config.ts
In docusaurus.config.ts, in the 'Products' footer column, add a new entry after DevoteMe (which is currently the last item in that column):
{label: 'DevoteMe', to: '/products/devoteme'},
{label: 'QuestKeeper', to: '/products/questkeeper'},
(Replace the single DevoteMe line with both lines above, so QuestKeeper becomes the new last entry in that column.)
- Step 3: Verify the config type-checks
Run: npm run typecheck
Expected: exits with no errors.
- Step 4: Commit
git add sidebars.ts docusaurus.config.ts
git commit -m "Register QuestKeeper docs sidebar and footer link"
Task 5: Docs — Overview, Installation, Commands, Permissions
Files:
- Create:
docs/products/questkeeper/index.md - Create:
docs/products/questkeeper/installation.md - Create:
docs/products/questkeeper/commands.md - Create:
docs/products/questkeeper/permissions.md
Interfaces:
-
Consumes: nothing (static content). Relative links (
./installation,./commands, etc.) must resolve to the files created in this task and in Task 6–7. -
Produces: the doc IDs
products/questkeeper/index,products/questkeeper/installation,products/questkeeper/commands,products/questkeeper/permissions, referenced by Task 4's autogenerated sidebar and by the "Where to Next" links below. -
Step 1: Create
docs/products/questkeeper/index.md
---
title: QuestKeeper
sidebar_label: Overview
sidebar_position: 1
description: Overview of QuestKeeper, the automatic daily quest plugin for Paper Minecraft servers powered by Citizens NPCs.
---
# QuestKeeper
A Paper Minecraft plugin that generates a new daily quest for your server every day, delivered through a Citizens NPC. Quests are automatically generated and validated across many types — delivering items, herding mobs, exploring biomes, discovering structures, fighting mobs, crafting, trading with villagers, and biome-specific gathering — with optional timed BossBar challenges. Players earn points and build streaks with no manual quest writing required.
:::note
QuestKeeper is currently **in development**. Configuration keys and behavior described here target version `0.1.0-SNAPSHOT`.
:::
---
## Why QuestKeeper
- **One shared goal per day** — a single active quest for the whole server; every player can complete it once.
- **No manual quest writing** — quests are generated and validated automatically from curated internal pools.
- **Delivered through an NPC** — players interact with a Citizens NPC to view and turn in their quest.
- **Modular quest-type framework** — a registry pattern means new quest types don't require touching core generation logic.
- **Points & streaks** — completing quests builds a daily streak that resets if a day is missed.
---
## Feature Summary
| Type | Completion | Description |
|---|---|---|
| `ITEM_DELIVERY` | NPC turn-in | Collect a set number of an item and right-click the NPC. Items are removed on success. |
| `MOB_DELIVERY` | NPC turn-in | Bring passive mobs within 6 blocks of the NPC. Mobs are removed on success. |
| `EXPLORATION` | Automatic | Visit a target biome (e.g. Desert, Jungle). Completes the instant you arrive. |
| `STRUCTURE_DISCOVERY` | Automatic | Find a generated structure (Village, Stronghold, Monument…) located via Paper structure APIs. |
| `COMBAT` | Automatic | Kill N of a mob. Only direct player kills count. |
| `CRAFTING` | Automatic | Craft N of an item. Only items crafted after the quest started count. |
| `VILLAGER_TRADING` | Automatic | Complete N villager trades. |
| `BIOME_COLLECTION` | Automatic | Collect items from their natural biome. Player-placed blocks never count. |
| `ESCORT` | *(roadmap)* | Experimental escort framework — architecture only, disabled by default. |
See [Quest Types](./quest-types) for full detail on pools, tiers, and timed quests.
---
## Requirements
| Dependency | Version |
|---|---|
| [Paper](https://papermc.io/) | 1.21.4+ |
| [Citizens](https://citizensnpcs.co/) | 2.x |
| Java | 21+ |
### Optional integrations
| Plugin | Effect |
|---|---|
| [ConsentPvP](https://github.com/AnchorlightDev/ConsentPvP) | Soft dependency. When installed, a player can only be teleported to (via `/tscroll player`) if they have consented. When absent, teleport consent checks are skipped. |
---
## Where to Next
- [Installation](./installation) — requirements, install steps, and building from source.
- [Commands](./commands) — every command and what it does.
- [Permissions](./permissions) — the full permission node list.
- [Configuration](./configuration) — annotated `config.yml` reference.
- [Quest Types](./quest-types) — every quest type, its pool, and timed quests.
- [Quest Shop](./shop) — spending Quest Points on scrolls, shields, and effects.
- [Data Files](./data-files) — `quest.yml`, `players.yml`, and `stats.yml`.
- [Troubleshooting & FAQ](./troubleshooting) — common questions and fixes.
- Step 2: Create
docs/products/questkeeper/installation.md
---
title: Installation
sidebar_label: Installation
sidebar_position: 2
description: How to install QuestKeeper, set up the quest NPC, and build the plugin from source.
---
# Installation
## Requirements
| Dependency | Version |
|---|---|
| [Paper](https://papermc.io/) | 1.21.4+ |
| [Citizens](https://citizensnpcs.co/) | 2.x |
| Java | 21+ |
## Steps
1. Drop `QuestKeeper-1.0.0-SNAPSHOT.jar` into your `plugins/` folder.
2. Ensure Citizens is installed and enabled.
3. Start (or reload) the server — the plugin generates its first quest automatically.
4. Create your quest-giver NPC with Citizens:
/npc create QuestKeeper
5. Note the NPC's ID from `/npc list`.
6. Open `plugins/QuestKeeper/config.yml` and set:
```yaml
quest-npc-id: <id>
- Reload the server or run
/questkeeper forcerefresh.
Players can now right-click the NPC to view and complete the daily quest.
Building from Source
git clone https://github.com/ModularSoftAU/QuestKeeper.git
cd QuestKeeper
mvn package
The built jar will be at target/QuestKeeper-1.0.0-SNAPSHOT.jar.
- [ ] **Step 3: Create `docs/products/questkeeper/commands.md`**
```md
---
title: Commands
sidebar_label: Commands
sidebar_position: 3
description: Every QuestKeeper command, its arguments, and what it does.
---
# Commands
Primary command: `/questkeeper` — Alias: `/qk`
## Player commands
| Command | Description |
|---|---|
| `/qk show` | Display today's active quest, target, and base reward. |
| `/qk points` | Show your own total points and current streak. |
| `/qk points <player>` | Show another player's points and streak. *(requires `questkeeper.admin`)* |
## Admin commands
*Requires the `questkeeper.admin` permission (default: op).*
| Command | Description |
|---|---|
| `/qk reroll` | Generate a new quest for today. Players who already completed the old quest keep their completion — rerolls only affect players who haven't submitted yet. Broadcasts the new quest to the server. |
| `/qk resetplayer <player>` | Clear a player's daily completion flag so they can submit again. Useful for testing or correcting mistakes. |
| `/qk forcerefresh` | Manually trigger the daily reset check right now. Use after changing `quest-npc-id` or to test date-change behavior. |
| `/qk stats` | Show aggregate statistics: quests generated/completed/failed, average completion time, and per-type usage. |
| `/qk debug` | Print internal plugin state: active quest, server date, and (if run as a player) your own profile data. |
## Other commands
| Command | Description | Permission |
|---|---|---|
| `/qshop` (alias `/questshop`) | Open the QuestKeeper Shop to spend Quest Points. | `questkeeper.use` |
| `/tscroll [player\|warp\|balance\|accept\|deny]` | Teleport Scroll — use scroll charges to teleport. | `questkeeper.scroll.use` |
| `/dailytask top [page]` | Daily task leaderboard. | `questkeeper.use` |
See [Quest Shop](./shop) for what `/qshop` and `/tscroll` do in detail.
- Step 4: Create
docs/products/questkeeper/permissions.md
---
title: Permissions
sidebar_label: Permissions
sidebar_position: 4
description: Full permission node reference for QuestKeeper.
---
# Permissions
| Permission | Default | Description |
|---|---|---|
| `questkeeper.use` | `true` | Use the daily quest system (NPC interaction, `/qk show`, `/qk points`). |
| `questkeeper.admin` | `op` | Access admin commands: `reroll`, `resetplayer`, `forcerefresh`, `stats`, `debug`, and viewing other players' points. |
| `questkeeper.scroll.use` | `true` | Use the Teleport Scroll system (`/tscroll`). |
- Step 5: Verify the four files exist with correct frontmatter
This site's docusaurus.config.ts sets onBrokenLinks: 'throw', so npm run build will fail at this point — index.md and commands.md link to ./configuration, ./quest-types, ./shop, ./data-files, ./troubleshooting, which don't exist until Tasks 6–7 land. Do not run npm run build in this task; that check only becomes meaningful once all 9 pages exist, which Task 8 verifies.
Instead, confirm the four files are well-formed:
Run: grep -c "^---$" docs/products/questkeeper/index.md docs/products/questkeeper/installation.md docs/products/questkeeper/commands.md docs/products/questkeeper/permissions.md
Expected: each file reports 2 (an opening and closing frontmatter delimiter).
Run: npm run start (backgrounded), then fetch http://localhost:3000/docs/products/questkeeper/, .../installation, .../commands, .../permissions and confirm each returns HTTP 200 with the expected <h1>. Dev mode (docusaurus start) does not run the broken-link check, so this validates rendering without the future-page links being an issue. Stop the dev server after checking.
- Step 6: Commit
git add docs/products/questkeeper/index.md docs/products/questkeeper/installation.md docs/products/questkeeper/commands.md docs/products/questkeeper/permissions.md
git commit -m "Add QuestKeeper overview, installation, commands, and permissions docs"
Task 6: Docs — Configuration and Quest Types
Files:
- Create:
docs/products/questkeeper/configuration.md - Create:
docs/products/questkeeper/quest-types.md
Interfaces:
-
Consumes: nothing new.
-
Produces: doc IDs
products/questkeeper/configurationandproducts/questkeeper/quest-types, linked from Task 5'sindex.md. -
Step 1: Create
docs/products/questkeeper/configuration.md
---
title: Configuration
sidebar_label: Configuration
sidebar_position: 5
description: Annotated config.yml reference for QuestKeeper.
---
# Configuration
`plugins/QuestKeeper/config.yml`
```yaml
# NPC ID of the quest giver (run /npc list to find it)
quest-npc-id: -1
# Server timezone for daily reset
# Examples: "UTC", "America/New_York", "Europe/London", "Asia/Tokyo"
timezone: "UTC"
# Streak bonus settings
streak:
bonus-per-day: 2 # Points added per streak day beyond the first
max-bonus: 10 # Maximum streak bonus
# Radius around the NPC to search for mobs (mob delivery quests)
mob-search:
horizontal-radius: 6.0
vertical-radius: 4.0
# Broadcast the new daily quest to all players when it changes
broadcast-new-quest: true
# Quest generator selection weights (relative; a weight of 0 disables a type)
quest-generator:
weights:
item_delivery: 25
mob_delivery: 20
exploration: 15
structure_discovery: 10
combat: 15
crafting: 10
villager_trading: 3
biome_collection: 2
# Timed quest modifier (BossBar countdown)
timed-quests:
chance: 0.15 # 0.0-1.0 probability an eligible quest becomes timed
min-seconds: 600
max-seconds: 1200
bonus-reward: 6 # extra points for finishing in time (currently overridden by the flat 1-point reward)
# Exploration / structure discovery
exploration:
structure-discovery-radius: 24 # blocks from a located structure to "discover" it
structure-search-radius: 6400 # locateNearestStructure search radius
# Escort quests (experimental roadmap feature — leave disabled)
escort:
enabled: false
```
:::note
`streak.bonus-per-day` and `streak.max-bonus` are retained for a future re-enable — every quest currently awards a flat **1 Quest Point** regardless of streak length. The same applies to `timed-quests.bonus-reward`.
:::
Persisted statistics live in `stats.yml`; per-player event-quest progress (and timed-quest state) is stored alongside player data so it survives restarts. See [Data Files](./data-files) for the full layout of both.
- Step 2: Create
docs/products/questkeeper/quest-types.md
---
title: Quest Types
sidebar_label: Quest Types
sidebar_position: 6
description: Every QuestKeeper quest type, its pool, tiers, timed-quest behavior, and roadmap frameworks.
---
# Quest Types
QuestKeeper uses a **modular quest-type framework** (registry pattern). Each type has its own generator and is validated automatically — adding a new type does not require touching the core generation logic.
Quest selection is weighted and configurable under `quest-generator.weights` (see [Configuration](./configuration)). Generated quests target a **5-30 minute** completion window for an average player (no Nether Stars, Elytra, Ancient Debris, or dragon kills). Quests are generated automatically from internal curated pools — no external config files are needed to define quests.
## Item delivery pool
Materials are drawn from an internal curated pool that covers common, farmable, and renewable items — things players are realistically expected to gather. The pool includes terrain blocks, logs, wool, farm produce, fish, mob drops, ores, and flowers.
Amount scales with rarity tier (the per-tier reward shown below is the generator's internal suggestion — it is currently overridden so **every quest awards a flat 1 Quest Point**):
| Tier | Example materials | Amount range |
|---|---|---|
| Very common | Dirt, Cobblestone, Sand | 48-64 |
| Common | Oak Log, Coal, Wheat, Feather | 24-48 |
| Uncommon | Iron Ingot, Bread, Slime Ball | 8-16 |
| Rare | Gold Ingot, Blaze Rod, Ender Pearl | 4-8 |
## Mob delivery pool
Only passive, herding-friendly mobs are included: **Cow, Sheep, Pig, Chicken, Rabbit, Goat**. Hostile mobs, bosses, water mobs, and villagers are excluded.
Mob amounts are intentionally low (2-5) since herding takes more effort than gathering items.
## Event quest pools
Event (auto-completing) quests draw from internal pools designed for a 5-30 minute completion window:
| Type | Pool / targets |
|---|---|
| Exploration | Desert, Jungle, Snowy Plains, Mushroom Fields, Badlands, Savanna, Taiga, Swamp, Plains, Forest |
| Structure Discovery | Village, Stronghold, Ocean Monument, Nether Fortress, Bastion Remnant, Pillager Outpost, Woodland Mansion, Desert Pyramid |
| Combat | Zombie, Skeleton, Creeper, Spider, Enderman (variants count: e.g. Stray/Bogged/Wither Skeleton → Skeleton; Husk/Drowned/Zombie Villager → Zombie; Cave Spider → Spider) |
| Crafting | Bread, Torch, Glass, Ladder, Stick, Chest, Furnace, Iron Chestplate, Cake |
| Villager Trading | Any completed trade, or trades involving a specific item drawn from across all professions (Wheat, Coal, Paper, Leather, Porkchop, Ink Sac, …). Item-specific trades are validated against the villager's live trade recipe. |
| Biome Collection | Snowballs (Snowy Plains), Cocoa Beans (Jungle), Cactus (Desert), Mushrooms (Mushroom Fields), Warped Fungus (Warped Forest) |
Biome-collection only credits **naturally generated** blocks broken in the target biome; blocks the player placed are tracked and never count.
## Timed quests
When the timed modifier applies (probability set by `timed-quests.chance`), an eligible quest gains a countdown rendered as a BossBar (`Quest Expires In: MM:SS`). The countdown starts the first time the player is seen with the quest that day. Running out of time fails the quest for the day. (A configured timed bonus exists but is currently overridden while all quests award a flat 1 point.)
## Repeat prevention
The generator will not produce the same type + target combination two days in a row (up to 20 retry attempts). The same logic applies when rerolling mid-day.
## Roadmap frameworks
- **Escort quests** — modular `EscortQuestService` behind the `escort.enabled` flag, disabled by default (architecture only).
- **Dynamic difficulty** — `QuestDifficulty` (EASY/NORMAL/HARD/ELITE) plus a `DifficultyCalculator` strategy interface, ready to weigh playtime, completions, streak, inventory value and XP level. The default calculator always returns `NORMAL`, so balance is unchanged until a real implementation is wired in.
- Step 3: Verify the files render correctly
This site's onBrokenLinks is 'throw', so npm run build will still fail at this point (configuration.md's config-page cross-link is fine, but index.md still links to ./shop, ./data-files, ./troubleshooting, which don't exist until Task 7). Do not run npm run build here; Task 8 covers that once all pages exist.
Run: npm run typecheck
Expected: exits with no errors (this task doesn't touch TypeScript, but confirms nothing else broke).
Run: npm run start (backgrounded), then fetch http://localhost:3000/docs/products/questkeeper/configuration and .../quest-types and confirm both return HTTP 200 with the expected <h1> and render the YAML/table content correctly (this also confirms the nested code fences in this task's Markdown source didn't corrupt rendering). Stop the dev server after checking.
- Step 4: Commit
git add docs/products/questkeeper/configuration.md docs/products/questkeeper/quest-types.md
git commit -m "Add QuestKeeper configuration and quest-types docs"
Task 7: Docs — Quest Shop, Data Files, Troubleshooting
Files:
- Create:
docs/products/questkeeper/shop.md - Create:
docs/products/questkeeper/data-files.md - Create:
docs/products/questkeeper/troubleshooting.md
Interfaces:
-
Consumes: nothing new.
-
Produces: doc IDs
products/questkeeper/shop,products/questkeeper/data-files,products/questkeeper/troubleshooting, completing every link referenced by Task 5'sindex.md. -
Step 1: Create
docs/products/questkeeper/shop.md
---
title: Quest Shop
sidebar_label: Quest Shop
sidebar_position: 7
description: What Quest Points can be spent on — Teleport Scrolls, Streak Shields, chat colors, and completion effects.
---
# Quest Shop
Open the shop with `/qshop` (alias `/questshop`, requires `questkeeper.use`) to spend Quest Points earned from completing daily quests.
## Teleport Scrolls
Used via `/tscroll [player|warp|balance|accept|deny]` (requires `questkeeper.scroll.use`):
- `/tscroll <player>` — request to teleport to another player.
- `/tscroll warp` — teleport to a configured warp.
- `/tscroll balance` — check remaining scroll charges.
- `/tscroll accept` / `/tscroll deny` — respond to an incoming teleport request.
When [ConsentPvP](./index#optional-integrations) is installed, `/tscroll player` only succeeds if the target has consented to being teleported to. Without ConsentPvP installed, this check is skipped. Scroll charges are tracked per player in `players.yml` (`scrollCharges`).
## Streak Shields
A one-use item that automatically protects a player's streak if they miss a day. Charges are tracked per player in `players.yml` (`streakShieldCharges`) and are auto-spent on a missed day.
## Timed Quest Extension
A shop item that adds time to an in-progress timed quest, giving players a way to buy extra room against the BossBar countdown described in [Quest Types](./quest-types#timed-quests).
## Chat Colors
A time-limited chat-colour pass. The active colour code and its expiry are tracked per player in `players.yml` (`chatColorCode`, `chatColorExpiryMillis`).
## Completion Effects
Players can unlock and select a visual effect that plays when they complete a quest. Unlocked effects and the currently selected one are tracked per player in `players.yml` (`unlockedEffects`, `selectedEffect`).
- Step 2: Create
docs/products/questkeeper/data-files.md
---
title: Data Files
sidebar_label: Data Files
sidebar_position: 8
description: The quest.yml, players.yml, and stats.yml files QuestKeeper maintains.
---
# Data Files
Both `quest.yml` and `players.yml` are created automatically in `plugins/QuestKeeper/`.
## `quest.yml`
Stores the current active quest. Regenerated each day.
```yaml
activeQuest:
date: "2026-03-11"
type: "ITEM_DELIVERY"
target: "OAK_LOG"
amount: 48
rewardPoints: 12
description: "Bring 48 Oak Logs to the Quest Keeper"
```
## `players.yml`
Stores per-player state. Updated immediately on quest completion.
```yaml
players:
123e4567-e89b-12d3-a456-426614174000:
lastCompletionDate: "2026-03-10" # used for streak logic
completedQuestDate: "2026-03-10" # used to block same-day re-submission
streak: 4
totalPoints: 87
scrollCharges: 2 # Teleport Scroll charges
questsCompleted: 130 # lifetime completions (leaderboard)
# Event-quest progress state (auto-completing quest types):
progressQuestDate: "2026-03-11" # quest day the progress applies to
progressCount: 3 # progress toward the active event quest
failedQuestDate: "" # set if a timed quest expired that day
timedStartMillis: 0 # epoch ms a timed quest started (0 = none)
progressMeta: {} # free-form (e.g. resolved structure coords)
# Shop perks:
streakShieldCharges: 1 # Streak Shields held (auto-spent on a missed day)
chatColorCode: "c" # active chat colour code ("" = none)
chatColorExpiryMillis: 0 # epoch ms the chat colour expires
unlockedEffects: [] # unlocked completion effects (enum names)
selectedEffect: "" # active completion effect ("" = none)
```
## `stats.yml`
Aggregate statistics surfaced by `/qk stats`.
```yaml
questsGenerated: 42
questsCompleted: 130
questsFailed: 7
totalCompletionSeconds: 5400 # used to derive average completion time
questTypeUsage:
item_delivery: 12
combat: 9
exploration: 6
```
- Step 3: Create
docs/products/questkeeper/troubleshooting.md
---
title: Troubleshooting & FAQ
sidebar_label: Troubleshooting
sidebar_position: 9
description: Common QuestKeeper issues and how to fix them.
---
# Troubleshooting & FAQ
## The NPC doesn't respond to right-clicks
- Confirm Citizens is installed and enabled — QuestKeeper depends on it.
- Confirm `quest-npc-id` in `config.yml` matches the NPC's ID from `/npc list`.
- After changing `quest-npc-id`, reload the server or run `/qk forcerefresh`.
## The quest didn't reset at midnight
QuestKeeper doesn't rely on exact-midnight timing. A background scheduler checks every **5 minutes** whether the server date (per the configured `timezone`) has changed, and generates a new quest when it does. If you need the reset to happen immediately, run `/qk forcerefresh` (requires `questkeeper.admin`).
## Points aren't increasing with my streak
This is expected current behavior, not a bug: every quest awards a flat **1 Quest Point**, regardless of streak length. The `streak.bonus-per-day` and `streak.max-bonus` config keys — and the timed-quest bonus reward — are retained for a future re-enable, but are not active yet. See [Configuration](./configuration).
## `/tscroll player` says the target hasn't consented
This only happens when [ConsentPvP](./index#optional-integrations) is installed. A player can only be teleported to via `/tscroll player` if they've opted in to consent. Without ConsentPvP installed, this check is skipped entirely.
## A reroll took away a player's completed quest
It shouldn't — `/qk reroll` only affects players who haven't submitted the old quest yet. Anyone who already completed it keeps their completion. If you're seeing otherwise, check `players.yml` for that player's `completedQuestDate` against the quest date in `quest.yml`.
- Step 4: Verify the full docs set builds with no broken links
Run: npm run build
Expected: build completes with exit code 0 and no broken-link warnings anywhere under docs/products/questkeeper/.
- Step 5: Commit
git add docs/products/questkeeper/shop.md docs/products/questkeeper/data-files.md docs/products/questkeeper/troubleshooting.md
git commit -m "Add QuestKeeper shop, data-files, and troubleshooting docs"
Task 8: Final verification pass
Files: none (verification only)
Interfaces:
-
Consumes: everything from Tasks 1-7.
-
Produces: nothing — this is the final gate confirming the whole feature is wired together correctly.
-
Step 1: Full production build
Run: npm run build
Expected: exit code 0, no broken-link warnings, no errors.
- Step 2: Type-check
Run: npm run typecheck
Expected: exit code 0, no errors.
- Step 3: Serve the production build and manually verify navigation
Run: npm run serve (in the background), then in a browser:
- Visit
http://localhost:3000/productsand confirm a QuestKeeper card appears. - Click through to
http://localhost:3000/products/questkeeperand confirm the landing page renders correctly. - Click "View Documentation" and confirm it lands on
http://localhost:3000/docs/products/questkeeper/with a working sidebar listing all 9 pages in order (Overview, Installation, Commands, Permissions, Configuration, Quest Types, Quest Shop, Data Files, Troubleshooting). - Click through each sidebar entry and confirm every page renders with no broken internal links.
- Scroll to the footer on any page and confirm the "QuestKeeper" link under Products navigates to
/products/questkeeper.
Stop the server after checking (Ctrl+C in that terminal).
- Step 4: Confirm git history is clean
Run: git log --oneline -8
Expected: one commit per task (Tasks 1-7), all present, nothing uncommitted.
Run: git status
Expected: nothing to commit, working tree clean.