generated from nholtware/service-template-express
feat: bundle Hansel and Gretel (public domain Grimm retelling)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
fc05a43264
commit
ef326a015e
2 changed files with 321 additions and 0 deletions
18
src/stories.test.ts
Normal file
18
src/stories.test.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { readdirSync, readFileSync } from "node:fs";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { analyze, storyInputSchema } from "./lib/story.js";
|
||||
|
||||
const dir = new URL("../stories/", import.meta.url);
|
||||
|
||||
describe("bundled stories", () => {
|
||||
const files = readdirSync(dir).filter((f) => f.endsWith(".json"));
|
||||
it("has at least one", () => expect(files.length).toBeGreaterThan(0));
|
||||
for (const f of files) {
|
||||
it(`${f} is valid, publishable, and has no warnings`, () => {
|
||||
const parsed = storyInputSchema.parse(
|
||||
JSON.parse(readFileSync(new URL(f, dir), "utf8")),
|
||||
);
|
||||
expect(analyze(parsed.doc)).toEqual([]);
|
||||
});
|
||||
}
|
||||
});
|
||||
303
stories/hansel-and-gretel.json
Normal file
303
stories/hansel-and-gretel.json
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
{
|
||||
"title": "Hansel and Gretel",
|
||||
"description": "A branching retelling of the Grimm fairy tale. Can you escape the forest and the witch?",
|
||||
"doc": {
|
||||
"start": "hunger",
|
||||
"nodes": {
|
||||
"hunger": {
|
||||
"title": "A hungry house",
|
||||
"text": "A famine has settled over the land, and the woodcutter's cottage is down to its last crust. You are Hansel, and your little sister Gretel lies beside you in the dark. Through the wall you hear your parents' voices, low and urgent.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Stay awake and listen at the door",
|
||||
"to": "overhear"
|
||||
},
|
||||
{
|
||||
"label": "Pull the blanket up and go to sleep",
|
||||
"to": "no-trail"
|
||||
}
|
||||
]
|
||||
},
|
||||
"overhear": {
|
||||
"title": "What the wall said",
|
||||
"text": "Your stepmother wants to lead you deep into the forest tomorrow and leave you there. Your father hates the idea, but he is tired and he gives way. Gretel starts to cry quietly.\n\nThe moon is bright outside.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Slip out and fill your pockets with white pebbles",
|
||||
"to": "pebbles"
|
||||
},
|
||||
{
|
||||
"label": "Tell Gretel not to worry; surely they would never do it",
|
||||
"to": "no-trail"
|
||||
}
|
||||
]
|
||||
},
|
||||
"pebbles": {
|
||||
"title": "Pockets full of moonlight",
|
||||
"text": "The pebbles gleam like silver coins. At dawn you each get a small piece of bread, and the whole family sets off into the trees.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Drop a pebble every few steps, quietly",
|
||||
"to": "home-again"
|
||||
},
|
||||
{
|
||||
"label": "Eat your bread and keep the pebbles for later",
|
||||
"to": "no-trail"
|
||||
}
|
||||
]
|
||||
},
|
||||
"home-again": {
|
||||
"title": "The way home",
|
||||
"text": "When the moon rises you and Gretel follow the pebbles, shining like a road, all the way back to the cottage. Your father weeps with relief. Your stepmother is not pleased.\n\nMonths pass. The famine deepens, and you overhear the same plan again.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Go out for pebbles again",
|
||||
"to": "locked-door"
|
||||
},
|
||||
{
|
||||
"label": "Hold back your bread and plan to leave crumbs instead",
|
||||
"to": "crumbs"
|
||||
}
|
||||
]
|
||||
},
|
||||
"locked-door": {
|
||||
"title": "A bolted door",
|
||||
"text": "This time your stepmother has locked the cottage door. There is no way out for pebbles, so in the morning you walk into the forest with nothing to mark the way.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Walk on, memorising what you can",
|
||||
"to": "forest-lost"
|
||||
}
|
||||
]
|
||||
},
|
||||
"crumbs": {
|
||||
"title": "Crumbs on the path",
|
||||
"text": "You crumble your bread along the trail as you walk. When night falls and you turn back, the path is bare. The birds have eaten every crumb.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Turn around and look for another way",
|
||||
"to": "forest-lost"
|
||||
}
|
||||
]
|
||||
},
|
||||
"no-trail": {
|
||||
"title": "Left behind",
|
||||
"text": "Your parents lead you deep into the trees, light a fire, and tell you to rest while they cut wood. You wake to cold ashes and the sound of wind. Nobody is coming back.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Take Gretel's hand and start walking",
|
||||
"to": "forest-lost"
|
||||
}
|
||||
]
|
||||
},
|
||||
"forest-lost": {
|
||||
"title": "Lost in the forest",
|
||||
"text": "You walk through two days and a night, hungry and frightened. The trees all look the same. On the third afternoon Gretel sits down on a root and will not get up.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Follow a snow-white bird singing ahead of you",
|
||||
"to": "bird"
|
||||
},
|
||||
{
|
||||
"label": "Climb the tallest tree and look for a way out",
|
||||
"to": "tree"
|
||||
},
|
||||
{
|
||||
"label": "Sit down beside her and rest",
|
||||
"to": "giveup"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bird": {
|
||||
"title": "The white bird",
|
||||
"text": "The bird sings a few notes, flutters ahead, and waits for you every time you fall behind. It leads you into a clearing, then lands on the roof of a small house and falls silent.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Look at the house",
|
||||
"to": "cottage"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tree": {
|
||||
"title": "From the treetop",
|
||||
"text": "Above the leaves you can see far. Away to the east a thin wisp of smoke rises from a strange little building in a clearing.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Climb down and head for it",
|
||||
"to": "cottage"
|
||||
}
|
||||
]
|
||||
},
|
||||
"giveup": {
|
||||
"title": "The long sleep",
|
||||
"text": "You curl up under the roots with Gretel. The forest is quiet and the leaves fall softly. In the morning, nobody wakes.",
|
||||
"ending": "lose"
|
||||
},
|
||||
"cottage": {
|
||||
"title": "A house made of sweets",
|
||||
"text": "The walls are gingerbread, the roof is cake, and the windowpanes are clear sugar. Your stomach hurts just looking at it.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Break off a piece of the roof and eat",
|
||||
"to": "eat"
|
||||
},
|
||||
{
|
||||
"label": "Knock politely at the door",
|
||||
"to": "knock"
|
||||
},
|
||||
{
|
||||
"label": "Walk all the way around the house first",
|
||||
"to": "circle"
|
||||
}
|
||||
]
|
||||
},
|
||||
"eat": {
|
||||
"title": "Nibble, nibble",
|
||||
"text": "As you chew, a voice calls from inside: \"Nibble, nibble, little mouse, who is nibbling at my house?\"\n\nYou answer, \"The wind, the wind, the heavenly child.\" The door opens and an old woman leans out on a crutch, smiling.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Let her welcome you inside",
|
||||
"to": "invite"
|
||||
},
|
||||
{
|
||||
"label": "Something is wrong; grab Gretel and run",
|
||||
"to": "run-away"
|
||||
}
|
||||
]
|
||||
},
|
||||
"knock": {
|
||||
"title": "A kind old woman",
|
||||
"text": "An old woman opens the door at once. \"You poor children. Come in, come in.\" There is warm milk and pancakes on the table.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Go inside",
|
||||
"to": "invite"
|
||||
},
|
||||
{
|
||||
"label": "Thank her, but walk on",
|
||||
"to": "run-away"
|
||||
}
|
||||
]
|
||||
},
|
||||
"circle": {
|
||||
"title": "What you notice",
|
||||
"text": "Around the back you see a very large oven, much too big for baking bread. Next to it lies a pile of small bones. Behind the curtain, two red eyes are watching you.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Quietly warn Gretel and leave",
|
||||
"to": "run-away"
|
||||
},
|
||||
{
|
||||
"label": "Go in anyway; you're desperate and she may not have noticed",
|
||||
"to": "invite"
|
||||
}
|
||||
]
|
||||
},
|
||||
"run-away": {
|
||||
"title": "Away from the sugar",
|
||||
"text": "You run until you cannot hear anyone behind you. It takes three more days, but at last the trees thin and a familiar stream appears. You reach your father's cottage at dusk.\n\nHe is alone. Your stepmother is gone. You will never learn what was in that house, and you do not ask.",
|
||||
"ending": "neutral"
|
||||
},
|
||||
"invite": {
|
||||
"title": "The soft bed",
|
||||
"text": "After the feast she shows you two small white beds. You and Gretel fall asleep thinking you are saved.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Sleep deeply, trusting her",
|
||||
"to": "cage"
|
||||
},
|
||||
{
|
||||
"label": "Pretend to sleep and watch her through your eyelashes",
|
||||
"to": "key"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cage": {
|
||||
"title": "The cage",
|
||||
"text": "At dawn the witch seizes you and locks you in a cage in the shed. \"Fatten him up,\" she cackles. Gretel is put to work. Each week the witch comes and says, \"Hansel, hold out your finger so I can feel if you're fat yet.\"\n\nHer eyes are bad. You find an old chicken bone in the straw.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Hold the bone out to her",
|
||||
"to": "bone"
|
||||
},
|
||||
{
|
||||
"label": "Slip out of the cage while she sleeps and look for the key",
|
||||
"to": "key"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bone": {
|
||||
"title": "The bony finger",
|
||||
"text": "\"Still so thin!\" the witch complains, week after week. Finally she loses patience. \"Gretel, light the oven! Tomorrow I eat him fat or thin.\"\n\nShe tells Gretel to crawl in and check if the oven is hot enough to bake the bread.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Pretend you don't know how to climb in",
|
||||
"to": "oven-trick"
|
||||
},
|
||||
{
|
||||
"label": "Beg for mercy",
|
||||
"to": "beg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"key": {
|
||||
"title": "The key",
|
||||
"text": "You find the key on a hook by the witch's bed. It is cold and heavy in your palm. Behind you, her breathing is slow and even.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Free Hansel and run at once",
|
||||
"to": "chase"
|
||||
},
|
||||
{
|
||||
"label": "Wait, and lure her toward the oven",
|
||||
"to": "oven-trick"
|
||||
}
|
||||
]
|
||||
},
|
||||
"beg": {
|
||||
"title": "No mercy",
|
||||
"text": "You plead and plead. The witch does not hear it, or does not care. She has been waiting a very long time for a meal like this.",
|
||||
"ending": "lose"
|
||||
},
|
||||
"oven-trick": {
|
||||
"title": "The witch and the oven",
|
||||
"text": "\"I don't know how,\" Gretel says. \"Show me.\" The witch grumbles, bends to the oven door, and shows her. With every ounce of strength, Gretel pushes.\n\nThe iron door slams. Gretel runs to free Hansel. The house is full of pearls and jewels.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Fill your pockets with jewels and go home",
|
||||
"to": "home-rich"
|
||||
}
|
||||
]
|
||||
},
|
||||
"chase": {
|
||||
"title": "The river",
|
||||
"text": "You run with the key as the dawn breaks. Behind you, the witch is awake and screaming. Ahead is a wide river with no bridge, just a white duck paddling in the shallows.",
|
||||
"choices": [
|
||||
{
|
||||
"label": "Ask the duck to carry you both at once",
|
||||
"to": "duck-both"
|
||||
},
|
||||
{
|
||||
"label": "Ask the duck to ferry you one at a time",
|
||||
"to": "duck-one"
|
||||
}
|
||||
]
|
||||
},
|
||||
"duck-both": {
|
||||
"title": "Too heavy",
|
||||
"text": "\"I am too small for two,\" says the duck, but you insist. Halfway across the river the duck dips beneath you, and the current takes you both. The witch watches from the bank.",
|
||||
"ending": "lose"
|
||||
},
|
||||
"duck-one": {
|
||||
"title": "One at a time",
|
||||
"text": "The duck carries Gretel first, then comes back for you. On the far bank the witch tries to follow, but she cannot cross. You walk home through a forest that now looks familiar.\n\nYou bring no treasure, only each other, and you are home.",
|
||||
"ending": "win"
|
||||
},
|
||||
"home-rich": {
|
||||
"title": "Home again",
|
||||
"text": "The woods open up and you see the cottage. Your father runs out to meet you. Your stepmother has died, and he has been sick with grief and regret ever since.\n\nYou tip the jewels onto the table. Hunger never comes to this house again, and you all live happily after.",
|
||||
"ending": "win"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue