Writing Emberfall Modules
A module is a plain text file. Paste it into the "Play your own module" box on the start screen and the game checks it and runs it. No AI is involved: the engine handles dice, fights, shops, rests, the map, and your hero's sheet. You write the story.
The smallest module
module: The Crossroads start: crossroads scene crossroads | You stand where two roads meet under a dead oak. choice: Take the left road -> left choice: Take the right road -> right scene left | The left road ends at a warm inn. You sleep well. end: victory scene right | The right road ends in a bog. You do not. end: defeat
Lines beginning with # are comments. Blank lines are ignored.
Header
The header sits above the first scene.
| Line | Meaning |
|---|---|
module: Title | Required. Shown on the start screen. |
start: scene_id | Required. The first scene. |
premise: text | One or two sentences shown on the start screen. |
author: name | Optional. |
id: short_name | Optional. Defaults to a slug of the title. |
Scenes
scene some_id starts a scene. Ids are letters, numbers, underscores, and hyphens. Everything until the next scene line belongs to it.
Prose
Use people: thatcher | pip inside a scene to show portraits of people physically present. Values are NPC IDs from lib/game/looks.ts, separated by |. Omit this directive when nobody should be pictured. Mentioning someone in dialogue does not imply their presence. This optional metadata is stored with new narration; older saves remain readable without it.
Lines starting with | are paragraphs shown to the player. Use *italics* and **bold**. You can drop the hero's details in with {name}, {calling}, {folk}, and {gold}.
A paragraph can carry the same requirements a choice can, written at the start of the line. It is read out only when they are met, so a scene can answer to what the hero actually did without splitting into a scene per combination.
| The abbey bell rings the hour, and the novices file in.
| {flag:aldous_turned} Aldous says the office himself, in his own voice, and does not hurry it.
| {!flag:aldous_turned} A novice says the office badly, because there is nobody left who says it well.
| {item:Tin Whistle} A boy's tin whistle is still in your pack, and you have still not learned to play it.Only braces at the front of the line are read as requirements, so {name} and prose that happens to contain a brace are left alone. A line whose requirements are not met is simply not said; nothing is greyed out and nothing is skipped over.
| **Reeve Thatcher** looks you over. "So you're {name}. A {calling}, are you?"Choices
choice: Label -> target_scene
Add a test in square brackets: the talent or stat, the difficulty, and optionally edge or burden. A test needs a fail target after |.
choice: Pick the lock [nimble 12] -> inside | alarm choice: Shoulder the door [might 16 burden] -> inside | hurt
Talents: athletics, brawl, stealth, nimble, survival, notice, lore, mysticism, healing, persuade, deceive, intimidate. Stats: might, grace, wits, presence. Difficulty: Easy 8, Standard 12, Hard 16, Heroic 20.
Add requirements in curly braces. A choice the hero does not qualify for shows greyed out with the reason, or add ?hidden to hide it entirely.
choice: Bribe the guard {gold:10} -> bribed
choice: Show the seal {item:silver_locket} -> recognized
choice: Mention the reeve's secret {flag:knows_secret} ?hidden -> leverage
choice: Ask as one Oracle to another {calling:oracle} -> blessing
choice: Read the runes {talent:lore} -> runes
choice: Go back {!flag:door_locked} -> hallRequirement kinds: flag, item, gold (minimum), calling, talent, companion, party, ally, hero, skill, deed (the last four are described further down). Put ! before any of them except gold, calling and talent to require its absence. calling and talent pass if anyone in the party has them; companion looks only at the companions, never the leader (see Parties and difficulty below).
Add a rest in parentheses. A breather heals 1d6 + level and half Energy, twice a day. A full rest restores everything.
choice: Sleep in the hayloft (rest full) -> morning choice: Catch your breath (rest breather) -> corridor
Effects
Effects apply when the scene is entered. Gold, experience, and items apply only the first time the player enters a scene, so revisiting a room does not pay out twice. Vitality, energy, flags, conditions, and quests apply every time.
| Line | Example | Notes |
|---|---|---|
gold: | gold: +12 or gold: -5 | Whole gold. |
xp: | xp: 25 | 150 Experience is a level. A chapter should pay out roughly 150 to 250 in total. |
vitality: | vitality: -3 | Damage or healing. |
energy: | energy: +2 | Casters only. |
heal: | heal: full | Full Vitality and Energy. |
item: | item: +healing_draught / item: -rope / item: +arrows*2 | Use catalogue ids or names for real gear. Any other name becomes a unique story item (a key, a token, a whistle) that can gate choices with {item:Name}. Separate several with |. |
flag: | flag: +met_reeve / flag: -has_torch | Flags gate choices. |
condition: | condition: +poisoned | Or -down to revive after a lose scene. |
quest: | quest: Title | active | note | Status: active, completed, failed. Same title updates. |
summary: | summary: In the reeve's kitchen. | Shown on the hero sheet. |
skill: | skill: +oath_of_the_wall | brann | Teaches a special skill (see Rewards below). The part after | is a premade id, leader, or all; left out, the first member who can learn it. |
talent: | talent: +lore / talent: +stealth | all | Trains a talent. Nobody is trained twice. |
deed: | deed: +tinkers_verse | Awards a deed and its title (see Rewards). |
Places and the map
place: Hallowmere | village place: The Deep Cellar | dungeon | from Hallowmere | N | near reveal: The Old Mill | ruin | W | far | Where the miller vanished.
place: moves the hero there and marks it visited. reveal: adds a place the hero has heard of without going there. Kinds: town, village, dungeon, ruin, wild, landmark, camp, shop, temple. Direction is one of N, NE, E, SE, S, SW, W, NW; distance is near, medium, or far, measured from the current place or from the named from place.
Shops
shop: Ma Cobbe | general | 1.2 | Rope, oil, and sheep-dip at moor prices.
Kinds: general, smith, herbalist, curios, shrine, fence. The number is a price multiplier (1 is list price). The shop panel opens when the scene is entered and closes when the player moves on.
Fights
List enemies, then the fight line with where to go on a win and on a loss. Optionally a flee target with the Grace difficulty to escape.
enemy: Bandit | guard 12 | vitality 9 | strike +3 | damage 1d6+1 enemy: Bandit Chief | guard 13 | vitality 14 | strike +4 | damage 1d8+2 | note scarred and shouting enemy: Hollowed Shepherd | guard 11 | vitality 10 | strike +3 | damage 1d6 | choir fight: bandits_dead | captured | flee road 12
Add choir to an enemy that belongs to the Choir (the hollowed, the echoes, anything with its mouths). Legendary gear and some skills answer the Choir. The engine also recognises the obvious names (Choir, Hollow, Echo, Shard, Glassborn, Drowned, Silence, Mouth, Voice, the Thing), but tag new ones.
During a fight the player chooses Strike, Defend, spells, knacks, items, or Flee each round, and the enemies strike back. The engine resolves it all. Reasonable numbers for level 1 to 3: guard 10 to 14, vitality 6 to 16, strike +2 to +5, damage 1d4 to 1d8+2. A boss for a level 3 hero: guard 13, vitality 22, strike +5, damage 1d8+3.
The lose scene is entered with the hero at 0 Vitality and the down condition. Use condition: -down and some healing there if the story spares them, or end: defeat if it does not.
Endings
end: victory end: defeat end: open
victory and defeat end the adventure. open marks a stopping point but lets the player keep the hero for a sequel. In the campaign, any ending but defeat offers the next chapter.
Campaigns, the world map, and flags that carry over
Emberfall ships with a chained campaign, The Unsealing. When a hero finishes a chapter with any ending except defeat, the ending panel offers the next chapter. The same hero continues with all gear, gold, experience, and every flag set so far. That means a later module can react to an earlier one:
choice: Show the reeve's letter {flag:shepherds_freed} -> warden_letter
choice: Tell her you will stop it {flag:promised_pip} -> wren_promiseFlags that other modules read, by the module that sets them. Every module sets more for its own use; grep its flag: + lines for the full set.
- The Whispering Barrow:
shepherds_freed,left_shepherds,barrow_singing(the first Silence is not shut),warden_loose(the barrow is quiet but its Warden walks the moor),promised_pip,knows_aldous,reeve_annoyed. - The Drowned Bell:
bell_sealed,bell_pinned,bell_corked,vane_revealed,vane_escaped,vane_dead,marisol_saved,cult_broken,cult_hostile,wanted,knows_rite,knows_keeper,met_cael,promised_wren,seraphine_marisol. - The Cold Choir:
third_sealed,aldous_turned,aldous_hurt,dun_saved_you,dun_watching,berra_hammer,berra_fair,brann_oath,osk_freed,stonekin_freed. - The Remembering Wood:
fourth_sealed,fifth_sealed,gate_resealed,gate_open,gate_weak_seal,wick_ally,tolly_saved,voices_freed,jars_smashed,six_freed,vane_turned,vane_dead,hale_turned,hale_captive,hale_witness,hale_dead,hale_fled,has_flame,hammer_in_oak,grusha_brother_sang,heard_aldous,heard_vane,knows_voice_market,knows_stone_word,ash_blessing,ash_spoke. - The Hollow Court:
sixth_sealed,well_weak_seal,well_lamps,chamberlain_dead,chamberlain_kept,chamberlain_taken,crane_voiced,regent_freed,penn_ally,penn_saved_you,hale_testified,market_ledger,jars_sold,hesper_brother_freed,knows_glass_caravan,has_court_lamp,shelves_seen,kael_ashwood. - The Glass Vault:
seventh_sealed,vault_weak_seal,vault_thin_salt,voices_carried,voices_fed,voices_left,ilyas_turned,ilyas_carrying,pym_dead,pym_captured,maud_passage,maud_returns_jars,maud_hoards,sailing_with_maud,nazreen_ally,npc_nazreen_book,tamsin_guide,tamsin_saved_you,camels,crates_to_shore,has_glass_lamp,knows_dune_sang. - The Cinder Choir:
ember_rekindled,campaign_complete,seraphine_brand, and for anything written after it,eighth_sealed,ninth_sealed,ninth_strong,cinder_weak_seal,fleet_ally,brand_ally,kell_turned,kell_dead,kell_fled,ember_held,ember_guttering. - The Silk Hand's Ledger (a side tale):
silk_ledger_burned,silk_ledger_penn,silk_ledger_lost,silk_guild_taken,silk_debts_burned, read by chapters 6 and 7. - What the Glass Kept (a side tale after chapter 6):
kept_names_read,kept_roll_kept,kept_roll_sold(the fate of the Roll of Ammar) andkept_senna_lost, read by chapter 7's epilogue, andkept_cut_closed. - The False Light (a side tale after chapter 7, so nothing reads it yet):
light_said_out,light_jar_broken,light_jar_given,light_jar_taken,light_due_paidandlight_true_light(the Old Beacon keeps an honest light),light_hanged,light_lied.
Keep flag names unique across modules, unless two modules mean exactly the same thing (vane_dead can be set in chapter 2 or chapter 4).
The world map (the World tab in play, and the atlas at /world) is authored in lib/world/world.ts: regions, places with coordinates, roads, and which chapter first touches each place. When a module's place: line uses a world place's name, that place lights up on the world map as visited. Add new regions and places there when you write a module in a new part of Aldermark; leave the module's own place: and reveal: lines for the local map.
To add a chapter to the campaign, put its text in lib/module/modules/, register the source in lib/module/catalog.server.ts (paid chapters are only ever sent from the server), give it an entry with its scene count in lib/module/catalog.ts, and add a row to CAMPAIGN.chapters in lib/campaign/campaign.ts. A free chapter is also bundled through FREE_SOURCES in lib/module/library.ts.
Parties and difficulty
The player may bring a party of up to three. You do not need to write for it: prose keeps saying "you" (the party is the "you"), a test is rolled by the member best suited to it, story damage and healing touch every member, and xp: is shared. Fights are scaled by the engine for the difficulty mode and party size, so write enemy numbers for a single hero on Normal. With companions along, a fight with two or more foes of the same name gains one more of them; a fight of named or lone foes gains nobody, and its foes get more Vitality and hit harder instead. Give rank-and-file foes the same name and bosses their own.
You may write for it when you want to. Two requirements look at who came along:
| {companion:brann} Brann puts his palm flat on the cairn and says nothing for a long time.
| {companion:hunter} Your hunter reads the mud and does not like it.
| {!party:2} You are alone on the causeway, and the fog knows it.
choice: Let Vesper try the lock {companion:vesper} ?hidden -> vault_open{companion:X}is met when a companion (not the leader) is the premadeX(brann,vesper,aldric,seraphine,kael,grusha) or has the callingX. A player leading as Brann does not hear Brann's companion lines: the leader is "you".{party:N}is met when the party has at least N members, leader included;{!party:2}means the hero is alone.
Keep companion beats optional colour. They must never be the only way forward, and a line must still read correctly when the lines around it are skipped. Name premades directly and write them in character (their personalities are in lib/game/premades.ts). Mark companion choices ?hidden so a player without that companion is not shown what they are missing.
Custom companions
A player can build their own companion. Custom characters have pronouns and may pick a drive: hunted, oathbound, seeker (searching for someone lost), lorehound (forbidden lore), faithful (faith tested), or glory, with a few words of detail ("my sister Ilse", "the Red Hand"). Premades never have a drive; they have their own lines above.
| {ally:seeker} {ally} asks the ferryman about {ally_detail}, the way {ally_they} ask{ally_s} everyone.
| {ally:stonekin} {ally} lays a palm on the lintel and reads the mason's marks.
| {ally:warden} {ally} puts {ally_their} shield between you and the door.
choice: Let {ally} speak to the widow {ally:faithful} ?hidden -> widow_faith{ally:X}is met when a custom companion (never a premade, never the leader) has the drive, calling or folkX, orany. With several{ally:...}on one line, one companion must meet them all.- In that line or choice,
{ally}is that companion's name. Pronouns:{ally_they}{Ally_they}{ally_them}{ally_their}{Ally_their}. Verb endings that agree with them:{ally_s}("walk{ally_s}"),{ally_is},{ally_has},{ally_was}. Use these only right after{ally_they}; with the name, write the verb plainly ("{ally} walks"). {ally_detail}is the drive's detail, or a fallback like "the one they lost" when the player left it blank. Write it where any short noun phrase reads well.{hero:X}looks at the leader instead: a premade id, or the leader's drive, calling or folk.
Do not use {companion:<calling>} for custom companions; it also matches premades. Use {ally:<calling>}.
Rewards: skills, talents, legendary gear, deeds
Side tales exist to be worth playing. They can hand out things the shops never sell:
- Skills (
skill: +id), used from the fight controls and recharging on a breather or a full rest. Ids and effects live inlib/game/legend.ts:oath_of_the_wall,silk_cut,unwritten_word,dawn_hymn,hunters_mark,clan_song,lantern_ward,salt_circle,ember_touch,wreckers_lantern. - Talent training (
talent: +id), usually from a mentor. Opens choices that ask for the talent. - Legendary gear (
item: +id), one of each, with effects shown on the sheet. Ids inlib/game/catalog.ts(LEGENDARY):ironvow_hammer,quills_last_knife,collegium_rod,dawnkeeper_cudgel,ashwood_bow,stonefist_greatblade,saltiron_blade,tidewrought_mail,glassward_shield,lampwarden_staff,beacon_coat. A replayed tale never gives a second. - Deeds (
deed: +id), each with a title, listed in the Legend tab with hints while unearned. Some are earned automatically from flags. Ids inlib/game/legend.ts.
Requirements can ask for them: {skill:dawn_hymn}, {deed:oath_kept}, {!deed:oath_kept}.
Side tales
A side tale is a module registered in SIDE_TALES (lib/campaign/campaign.ts) with the chapter it follows (7 means once the campaign is finished; there is no next chapter to return to), a region, and optionally a premade who must be in the party. It is offered at the end of that chapter and stays on the shelf in the Legend tab. It starts with the campaign's flags and the party as they are, and when it ends (even in defeat) the party carries on to the next chapter. Write a tale's endings as end: victory or end: open; a tale's end: defeat sends the party back to the road with nothing, which is fine for a real loss.
A tale can be replayed for the story, but gold, experience and items pay out only the first time it is finished. Keep a tale's rewards modest: roughly 150 to 250 experience across the tale, and its legendary gear, skill, training and deed at its end.
Checking your module
The paste box reports errors with line numbers: unknown scene targets, tests without fail targets, unknown talents, skills or deeds, scenes with no way out. An item name the catalogue does not know is not an error: it becomes a story item. Fix them until it says "Looks good".
Tips
- Give most scenes two to four choices. One choice reads as a railroad; six reads as a menu.
- Let failed tests lead somewhere interesting rather than to a dead end.
- Use flags for knowledge:
flag: +knows_passwordin one scene,{flag:knows_password}on a choice elsewhere. - Reward exploration with small
xp:andgold:payouts, and keep the big ones for endings. - Put a breather or shop before a boss.
- Aim for 25 to 60 scenes for an evening's play.