Your First Game
This guide walks through the starter game created by the scaffolder to explain how everything fits together.
Game Configuration
Section titled “Game Configuration”Every game starts with content/game.yaml:
id: gamestartLocation: tavernstartTime: day: 1 hour: 8startFlags: {}startVariables: gold: 100 reputation: 0startInventory: []This sets the player’s starting location, time, variables, and inventory.
Adding a Location
Section titled “Adding a Location”Create content/locations/tavern.yaml:
id: tavernname: 'The Salty Dog'description: 'A cozy tavern with worn wooden tables and the smell of hearth smoke.'banner: tavern.pngmusic: tavern_ambience.oggambient: ''Text can be written inline like this, or as localization keys (@location.tavern.name) that resolve from a locale file. Inline text is simpler for getting started. See Localization when you’re ready to support multiple languages.
Adding a Character
Section titled “Adding a Character”Create content/characters/bartender.yaml:
id: bartendername: 'Greta'biography: 'The no-nonsense owner of the Salty Dog.'portrait: bartender.pnglocation: taverndialogue: bartender_greetingstats: {}The location field places the character at the tavern. The dialogue field points to the dialogue file that plays when the player talks to them.
Writing a Dialogue
Section titled “Writing a Dialogue”Create content/dialogues/bartender_greeting.dlg:
NODE start BARTENDER: "Welcome to the Salty Dog! What can I do for you?"
CHOICE "Any news around town?" SET flag metBartender ADD relationship bartender 1 GOTO rumors END
CHOICE "Nothing, just looking around." GOTO farewell END
NODE rumors BARTENDER: "Word is there's a merchant in the market square looking for help with deliveries." GOTO farewell
NODE farewell BARTENDER: "Come back anytime!" END dialogueKey concepts:
NODEdefines a conversation pointBARTENDER:sets the speaker (matches character ID, case-insensitive)CHOICEblocks define what the player can say- Effects like
SET flagandADD relationshipmodify game state END dialoguecloses the conversation
Text is written inline with quotes here. When you’re ready to support multiple languages, move text to a locale file and use @key references. See Localization.
Running Your Game
Section titled “Running Your Game”npm run devThe dev server:
- Loads all content from
content/ - Parses
.dlgfiles into dialogue entities - Serves content via
/api/content - Watches for file changes and hot-reloads
Open http://localhost:3000 to see your tavern, talk to the bartender, and explore your game.
The App Component
Section titled “The App Component”The scaffolded src/App.tsx uses GameShell, a complete wrapper that provides splash screen, title screen, pause menu, settings, and video support out of the box:
import { useEffect, useState } from 'react';import type { ContentRegistry, GameConfig, AssetManifest,} from '@doodle-engine/core';import { GameShell } from '@doodle-engine/react';
export function App() { const [content, setContent] = useState<{ registry: ContentRegistry; config: GameConfig; manifest: AssetManifest; } | null>(null);
useEffect(() => { Promise.all([ fetch('/api/content').then((res) => res.json()), fetch('/api/manifest').then((res) => res.json()), ]).then(([contentData, manifestData]) => { setContent({ registry: contentData.registry, config: contentData.config, manifest: manifestData, }); }); }, []);
if (!content) return ( <div className="app-bootstrap"> <div className="spinner" /> </div> );
return ( <GameShell registry={content.registry} config={content.config} manifest={content.manifest} title="My Game" subtitle="A text-based adventure" availableLocales={[{ code: 'en', label: 'English' }]} /> );}GameShell handles the full game lifecycle. You just provide content and configuration. See Game Shell for customization options.
Next Steps
Section titled “Next Steps”- Game Shell: splash screen, title, pause menu, settings
- Writing Dialogues: branching conversations, conditions, effects
- Creating Quests: multi-stage quest tracking
- Adding Locations: maps and travel