Recipes, scenarios, and simulation
Recipes describe board intent. Scenarios add game content. Simulation scripts exercise the same public API a game loop would use.
Recipes
Section titled “Recipes”A recipe is the smallest useful serialized authoring format. It can contain:
- a board shape and seed.
- explicit tile or placement steps.
- layout archetypes local to the recipe.
- generated
layoutFillsfor built-in archetypes. - generated
pieceDeclarationsandpieceFillsfor custom packs. - manifest validation requirements.
Use recipes when a board needs to be saved, generated by tools, checked into a game repository, or reviewed in documentation.
import { createGameboardPlanFromRecipe, inspectGameboardRecipe,} from 'declarative-hex-worlds/recipe';import { freeManifest } from 'declarative-hex-worlds/manifest/free';
const preflight = inspectGameboardRecipe(recipeJson, { plan: { assetCatalog: freeManifest },});
const recipeErrors = preflight.violations.filter((issue) => issue.severity === 'error');if (recipeErrors.length > 0) { throw new Error(recipeErrors.map((issue) => issue.message).join('\n'));}
const plan = createGameboardPlanFromRecipe(recipeJson);Recipe generation should be deterministic. Use one seed for board terrain and a separate seed namespace for layout fills, piece fills, spawn groups, or patrols when a game needs stable diffs.
Layout And Piece Fills
Section titled “Layout And Piece Fills”Layout fills are the core random-board primitive. They combine a placement role, candidate-site criteria, density or count, and deterministic scoring.
Common cases:
- trees use scatter or tree archetypes, often with
fill,maxCount,maxPerTile, and a shared slot group. - harbors use coast tiles adjacent to water.
- landmarks and towers use larger footprints and occupancy reservations.
- units use spawn-like criteria and usually remain low-density.
- loose props can allow occupied tiles if they use a non-blocking slot group.
Piece fills are the custom-pack version of layout fills. They select reusable piece declarations by id, asset id, role, source, tag, or local-only state, then expand the selection into deterministic layout rules.
Run analysis before committing generated placements into a plan or runtime:
import { analyzeGameboardLayoutFill } from 'declarative-hex-worlds/layout';import { inspectSeededGameboardPieceFills } from 'declarative-hex-worlds/rules';
const layoutReport = analyzeGameboardLayoutFill(plan, layoutFill);const pieceReport = inspectSeededGameboardPieceFills(plan, registry, pieceFills, { seed: 'campaign-01:custom-pieces',});Warnings are useful, not cosmetic. A low candidate count, clamped fill count, or large footprint rejection usually means the authored board cannot support the requested density.
Scenarios
Section titled “Scenarios”A scenario combines a recipe with gameplay objects:
- named spawn groups.
- patrol route plans.
- actors, including players, NPCs, enemies, props, blockers, and interactives.
- movement agents and movement profiles.
- patrol agents.
- quests.
- renderer source URL maps for local custom pieces.
Scenarios are the preferred test fixture for integration and browser coverage because they force consumers to use the package the way a game does.
import { createGameboardRuntimeFromScenario } from 'declarative-hex-worlds/runtime';import { validateGameboardScenario } from 'declarative-hex-worlds/scenario';
const validation = validateGameboardScenario(scenarioJson, { plan: { assetCatalog: manifest },});
const scenarioErrors = validation.filter((issue) => issue.severity === 'error');if (scenarioErrors.length > 0) { throw new Error(scenarioErrors.map((issue) => issue.message).join('\n'));}
const runtime = createGameboardRuntimeFromScenario(scenarioJson);Scenario validation should fail duplicate ids, unresolved spawn groups, duplicate spawn-location claims, missing patrol routes, broken actor references, broken quest references, missing manifest assets, and invalid runtime placement requests.
Simulation Scripts
Section titled “Simulation Scripts”Simulation scripts are deterministic headless game-loop tests. They can run:
- movement commands.
run-systemsticks for patrols, movement, commands, actor targets, and quests.- command previews and command execution.
- actor-target inspections and chosen-target dispatch.
- actor spawn, update, and removal mutations.
- placement spawn, update, move, and removal mutations.
- expectation checks against actors, quests, movement, events, commands, and final placement records.
import { runGameboardScenarioSimulationScript, validateGameboardScenarioSimulationScript,} from 'declarative-hex-worlds/simulation';
const scriptValidation = validateGameboardScenarioSimulationScript(scriptJson, { scenario: scenarioJson,});
const simulationErrors = scriptValidation.filter((issue) => issue.severity === 'error');if (simulationErrors.length > 0) { throw new Error(simulationErrors.map((issue) => issue.message).join('\n'));}
const result = runGameboardScenarioSimulationScript(scenarioJson, scriptJson);The SimpleRPG fixtures in the package are the canonical acceptance shape. They
spawn a player, traverse a fixed board, classify props and enemies through
public actor APIs, advance quests, and exercise seeded content through the same
scenario and simulation layer. The packaged usage example also exposes
summarizeSimpleRpgGuidePublicApiExercises(), which joins every current
guide-facing public API to SimpleRPG evidence so app smoke tests can fail on
missing or stale guide/API representation. Evidence modes are memberships, not
exclusive buckets, so one API can be executable smoke and also prove seeded
generation, blueprint compilation, manifest packaging, compatibility adapters,
or visual coverage. Its executable helper smoke directly
invokes 40 guide-facing helper APIs and checks the 404 KayKit public treatment
records plus all 19 decomposed guide pages, so catalog coverage is exercised
through package imports as well as the generated ledger.
CLI Flow
Section titled “CLI Flow”Use the CLI to preflight serialized content outside a test runner:
declarative-hex-worlds validate-recipe \ --recipe docs/examples/generated-piece-scenario.recipe.json \ --outPlan /tmp/generated-piece-scenario.plan.json
declarative-hex-worlds validate-scenario \ --scenario <your-scenario.json> \ --manifest assets/free/manifest.json \ --outPlan /tmp/simple-rpg-plan.json
declarative-hex-worlds validate-simulation \ --scenario <your-scenario.json> \ --script <your-simulation-script.json> \ --manifest assets/free/manifest.json
declarative-hex-worlds simulate-scenario \ --scenario <your-scenario.json> \ --script <your-simulation-script.json> \ --manifest assets/free/manifest.json \ --out /tmp/simple-rpg-simulation.json \ --outInterop /tmp/simple-rpg-interop.jsonFor browser E2E, render the same scenarios rather than creating private renderer-only fixtures. That keeps screenshots tied to the public contract.