CLI Commands
The @doodle-engine/cli package provides four commands: doodle create, doodle dev, doodle build, and doodle validate.
In a scaffolded project, these are wired up as npm scripts:
npm run devrunsdoodle devnpm run buildrunsdoodle buildnpm run validaterunsdoodle validatenpm run previewrunsvite preview
doodle create
Section titled “doodle create”Scaffold a new game project.
npx @doodle-engine/cli create <project-name>Prompts
Section titled “Prompts”- Use default renderer? Yes uses
GameRendererfor a complete out-of-the-box UI. No sets up a skeletonApp.tsxwithuseGamefor building a custom renderer.
What it creates
Section titled “What it creates”<project-name>/ content/ characters/bartender.yaml, merchant.yaml dialogues/tavern_intro.dlg, market_intro.dlg, bartender_greeting.dlg, merchant_intro.dlg, bluff_check.dlg interludes/chapter_one.yaml items/old_coin.yaml journal/tavern_discovery.yaml, odd_jobs_accepted.yaml, market_square.yaml locales/en.yaml locations/tavern.yaml, market.yaml maps/town.yaml quests/odd_jobs.yaml game.yaml assets/ images/ audio/ fonts/ maps/ src/ main.tsx App.tsx index.css index.html package.json tsconfig.json .gitignorePost-install
Section titled “Post-install”cd <project-name>npm installnpm run devdoodle dev
Section titled “doodle dev”Start the development server with content hot-reload.
npm run devWhat it does
Section titled “What it does”- Starts a Vite dev server on port 3000
- Loads all content from
content/directory - Parses
.yamlfiles as entities and.dlgfiles as dialogues - Serves content via the
/api/contentendpoint as JSON - Generates asset manifest on-the-fly and serves it at
/api/manifest - Watches
content/**/*for changes using chokidar - Validates content on every file change and prints errors to the terminal
- Triggers full page reload when content files change
- Exposes
window.doodledev tools API in the browser console (dev mode only)
Content loading
Section titled “Content loading”| Directory | File Type | How it’s loaded |
|---|---|---|
characters/ | .yaml | Parsed as Character entity |
dialogues/ | .dlg | Parsed with parseDialogue() |
interludes/ | .yaml | Parsed as Interlude entity |
items/ | .yaml | Parsed as Item entity |
journal/ | .yaml | Parsed as JournalEntry entity |
locales/ | .yaml | Loaded as flat key-value dict, keyed by filename |
locations/ | .yaml | Parsed as Location entity |
maps/ | .yaml | Parsed as Map entity |
quests/ | .yaml | Parsed as Quest entity |
game.yaml | .yaml | Parsed as GameConfig |
/api/content response
Section titled “/api/content response”{ "registry": { "locations": { ... }, "characters": { ... }, "items": { ... }, "maps": { ... }, "dialogues": { ... }, "quests": { ... }, "journalEntries": { ... }, "interludes": { ... }, "locales": { ... } }, "config": { "startLocation": "tavern", "startTime": { "day": 1, "hour": 8 }, ... }}Content validation
Section titled “Content validation”When content files change, the dev server automatically validates:
- Dialogue structure: GOTO targets exist, no duplicate node IDs, startNode exists
- Conditions & Effects: Required arguments are present (e.g.,
hasFlagneedsflag,setVariableneedsvariableandvalue) - Character references: Characters’ dialogue IDs point to existing dialogues
- Localization keys: All
@keyreferences exist in locale files
Validation errors are printed to the terminal but do not stop the dev server. You can continue working while fixing errors.
Example validation output:
✗ Found 2 validation errors:
content/dialogues/bartender_greeting.dlg Node "greet" GOTO "invalid_node" points to non-existent node Add NODE invalid_node or fix the GOTO target
content/characters/merchant.yaml Character "merchant" references non-existent dialogue "merchant_chat" Create dialogue "merchant_chat" or fix the referenceDev Tools API
Section titled “Dev Tools API”In development mode, a window.doodle object is exposed in the browser console with debugging utilities:
// Flag manipulationdoodle.setFlag('quest_started');doodle.clearFlag('quest_started');
// Variable manipulationdoodle.setVariable('gold', 100);doodle.getVariable('gold');
// Location controldoodle.teleport('tavern');
// Dialogue controldoodle.triggerDialogue('bartender_greeting');
// Quest controldoodle.setQuestStage('odd_jobs', 'in_progress');
// Inventory controldoodle.addItem('old_coin');doodle.removeItem('old_coin');
// Inspectiondoodle.inspect(); // Show current state and available commandsdoodle.inspectState(); // Return full game state objectdoodle.inspectRegistry(); // Return content registry objectDev tools are automatically removed from production builds via Vite’s tree-shaking.
doodle build
Section titled “doodle build”Build the game for production.
npm run buildWhat it does
Section titled “What it does”- Validates all content first and fails if errors are found
- Runs a Vite production build
- Outputs to
dist/directory - Bundles and optimizes all assets
- Strips dev tools from production bundle
- Generates
dist/asset-manifest.jsonlisting all game assets with types, sizes, and tiers - Generates
dist/sw.js, a service worker that precaches all assets for offline play - Writes manifest to
dist/api/manifestsovite previewcan serve it
If validation errors are found, the build will exit with code 1 and display the errors. Fix all validation errors before deploying to production.
Preview
Section titled “Preview”After building, preview the production build:
npx vite previewdoodle validate
Section titled “doodle validate”Validate all game content without building or running the dev server.
npm run validateWhat it validates
Section titled “What it validates”- Dialogue structure
startNodeexists in dialogue- No duplicate node IDs within a dialogue
- All GOTO targets (from
node.next,choice.next,conditionalNext) point to existing nodes
- Conditions
hasFlag/notFlaghaveflagargumenthasItem/notItemhaveitemargumentquestAtStagehasquestandstageargumentsvariableEquals/variableGreaterThan/variableLessThanhavevariableandvaluearguments
- Effects
setFlag/clearFlaghaveflagargumentsetVariable/addVariablehavevariableandvalueargumentsaddItem/removeItemhaveitemargumentmoveItemhasitemandlocationargumentssetQuestStagehasquestandstageargumentsaddJournalEntryhasentryargumentsetCharacterLocationhascharacterandlocationargumentsaddToParty/removeFromPartyhavecharacterargumentsetRelationship/addRelationshiphavecharacterandvalueargumentssetCharacterStat/addCharacterStathavecharacter,stat, andvalueargumentssetMapEnabledhasenabledargumentadvanceTimehashoursargumentgoToLocationhaslocationargumentstartDialoguehasdialogueargumentplayMusic/playSoundhavefileargumentplayVideohasfileargumentnotifyhasmessageargumentshowInterludehasinterludeIdargumentrollhasvariable,min, andmaxarguments
- Character dialogue references
- Characters’
dialoguefield points to existing dialogue IDs
- Characters’
- Localization keys
- All
@keyreferences in locations, characters, items, quests, journal entries, dialogues, and interludes exist in at least one locale file
- All
Exit codes
Section titled “Exit codes”- 0: No validation errors found
- 1: Validation errors found
Example output
Section titled “Example output”🐾 Validating Doodle Engine content...
✓ No validation errorsOr with errors:
🐾 Validating Doodle Engine content...
✗ Found 3 validation errors:
content/dialogues/bartender_greeting.dlg Node "greet" GOTO "continue" points to non-existent node Add NODE continue or fix the GOTO target
content/dialogues/bartender_greeting.dlg Node "ask_rumors" condition "hasFlag" missing required "flag" argument
content/characters/merchant.yaml Character "merchant" references non-existent dialogue "merchant_chat" Create dialogue "merchant_chat" or fix the referenceWhen to use
Section titled “When to use”- Before committing: Validate content changes before pushing to version control
- CI/CD pipelines: Add
npm run validateto your CI workflow to catch content errors early - Manual testing: Run validation without starting the full dev server