Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apursley2012/the-beach-mystery/llms.txt

Use this file to discover all available pages before exploring further.

Before the story begins, The Beach Mystery asks you five questions. The answers you provide are stored as named variables in the game state and substituted directly into story text wherever a matching {placeholder} appears. This means the chest holds the exact jewel you named, the watch beside it shows your favorite cartoon character, and the island guardian takes the form of your favorite animal — the story speaks to you, not just about you.

How Substitution Works

When you complete the personalization questions, your five answers are saved into the variables object inside the game state alongside a formatted_time value stamped at the moment you begin:
{
  "variables": {
    "firstName": "Alex",
    "favoriteColor": "crimson",
    "favoriteAnimal": "fox",
    "cartoonChar": "Totoro",
    "favoriteJewel": "ruby",
    "formatted_time": "14:32"
  }
}
Every story line that contains a placeholder in curly braces is passed through an interpolate function before it is rendered on screen. The function replaces each {placeholder} token with the corresponding variable value (or a fallback if the value is missing):
const interpolate = (text, variables) =>
  text
    .replace(/\{firstName\}/g, variables.firstName || 'traveler')
    .replace(/\{favoriteColor\}/g, variables.favoriteColor || 'blue')
    .replace(/\{favoriteAnimal\}/g, variables.favoriteAnimal || 'cat')
    .replace(/\{cartoonChar\}/g, variables.cartoonChar || 'Mickey')
    .replace(/\{favoriteJewel\}/g, variables.favoriteJewel || 'ruby')
    .replace(/\{formatted_time\}/g, variables.formatted_time || '12:00');
This replace chain runs against every narration line as the story renders — not at startup. That means the substitution always uses the current variable values, and future story nodes benefit automatically if variables were to change.

The Five Questions

Each question has an id that maps to a variable key, a label shown on screen, a placeholder shown inside the text input, and a hint explaining how the answer will appear in the story.
FieldValue
IDfirstName
LabelWhat is your first name?
PlaceholderEnter your name…
HintUsed to greet you at the start of your adventure.
Fallbacktraveler
Your name appears in the very first line of the story ("Hello, {firstName}!") and is woven into narration throughout the adventure to address you directly.
FieldValue
IDfavoriteColor
LabelWhat is your favorite color?
PlaceholderA color that catches your eye…
HintColors the jewel you may discover.
Fallbackblue
The color is paired directly with your jewel name. If you open the chest the narration reads: "you find an old treasure map and one brilliant {favoriteColor} {favoriteJewel}." It also describes the jewel’s glow inside the cave and on the island.
FieldValue
IDfavoriteAnimal
LabelWhat is your favorite animal?
PlaceholderA creature you love…
HintMay appear during your adventure.
Fallbackcat
Your animal appears in two storylines. On the island, a {favoriteAnimal} sleeps beside the treasure under the oak tree. In the cave’s right passage, a {favoriteAnimal} curled in a cozy den becomes the guardian that shows you the way out.
FieldValue
IDcartoonChar
LabelWho is your favorite cartoon character?
PlaceholderA character you adore…
HintFeatured on the watch you check beside the chest.
FallbackMickey
When you discover the chest, the narration reads: "You brush the sand from its heavy lid and glance at your {cartoonChar} watch." It is a small, playful detail — but it grounds the moment in your world.
FieldValue
IDfavoriteJewel
LabelWhat is your favorite jewel?
PlaceholderA gemstone you treasure…
HintThe jewel hidden inside the pirate chest.
Fallbackruby
The jewel appears more than any other variable. It names the item in your inventory sidebar, is described when you open the chest, glows to light your way through the cave, fits into the stone pedestal in the hidden chamber, and is referenced in the ending summary if you carried it home.

Example Substitution

A raw story line before substitution:
"Inside, wrapped in faded blue cloth, you find an old treasure map and one brilliant {favoriteColor} {favoriteJewel}."
After interpolate runs with favoriteColor = "crimson" and favoriteJewel = "ruby":
"Inside, wrapped in faded blue cloth, you find an old treasure map and one brilliant crimson ruby."
The same mechanism applies to every line that contains a placeholder token — the narration, choice prompts, riddle hints, and ending summaries all pass through the same function.

Fallback Values

Every placeholder has a fallback string used when the variable is empty or missing. This ensures the story remains grammatically complete even if a field was skipped or the game state was loaded from a partial save.
VariableFallback
{firstName}traveler
{favoriteColor}blue
{favoriteAnimal}cat
{cartoonChar}Mickey
{favoriteJewel}ruby
{formatted_time}12:00
formatted_time is not a question — it is set automatically to the current HH:MM clock time at the moment you click Begin Adventure →. It appears in the chest discovery scene when you glance at your watch. There is no question for it and no user-facing input.

Tips for Best Results

Shorter answers read most naturally once substituted. "fox" reads better than "a cute red fox" because the story already supplies surrounding words. "sapphire" works better than "my favourite sparkly blue gem". One or two words per answer is ideal.
There is no validation on any of the five fields — you can enter anything. Emoji, phrases, or even a full sentence will be substituted verbatim. The results can be delightfully strange. Try it.

For Developers: Where Substitution Lives

The interpolation function is defined inline inside the /play page component (main.js) and called on every narration line as it is revealed during the typewriter animation:
const interpolate = (text, variables) =>
  text
    .replace(/\{firstName\}/g, variables.firstName || 'traveler')
    .replace(/\{favoriteColor\}/g, variables.favoriteColor || 'blue')
    .replace(/\{favoriteAnimal\}/g, variables.favoriteAnimal || 'cat')
    .replace(/\{cartoonChar\}/g, variables.cartoonChar || 'Mickey')
    .replace(/\{favoriteJewel\}/g, variables.favoriteJewel || 'ruby')
    .replace(/\{formatted_time\}/g, variables.formatted_time || '12:00');
Story lines in data/story.js use the raw {placeholder} tokens and are never pre-interpolated. This keeps the story data clean and makes it straightforward to add new variables: add the question to PERSONALIZATION_QUESTIONS, add the variable to the startGame call in useGameState.js, add a .replace() call to interpolate, and use the new {placeholder} token anywhere in STORY_NODES.
Variable values are stored in gameState.variables and are included in the localStorage save snapshot under beach-mystery-save. If a player saves mid-story and resumes later, all five personalization values are restored from the saved state and substitution continues exactly as before.

Build docs developers (and LLMs) love