Skip to content

Architecture

The library is one published npm package (declarative-hex-worlds) that internally decomposes into 20 domain sub-packages under src/. Cross-domain imports traverse barrel re-exports only — Biome’s noRestrictedImports rule enforces it.

Sub-packagePurposePublic surface
traits/koota trait declarations (37 traits)declarative-hex-worlds/traits
types/Branded primitives + interface definitionsdeclarative-hex-worlds/types
coordinates/Hex algebra, projection, grid layout, world↔hex transforms/coordinates, /grid, /layout, /projection
manifest/KayKit pack manifest schema + the autogenerated FREE manifest/manifest/schema, /manifest/free
ingest/Node-side asset ingest, source-root validation, manifest generation/ingest
cli/commands/bootstrap/CLI bootstrap subcommand + programmatic API; downloads + verifies KayKit assets; layout descriptors/bootstrap, /bootstrap/upstream-layout
gameboard/Tile + placement + plan builders, occupancy, navigation/gameboard, /navigation, /occupancy
pieces/Custom piece declarations + cross-kit compatibility/pieces
rules/Plan + scenario validation, layout fill rules/rules, /validation, /rule-types
scenario/Recipe → blueprint → scenario compilation, catalog/scenario, /recipe, /blueprint, /catalog, /registry
actors/Actor traits, queries, registration, navigation profiles, targets/actors
movement/Movement agents + step execution/movement
patrol/Patrol routes + assignment + scripted patrol simulation/patrol
quests/Quest entities, objectives, progress, completion/quests
commands/Interaction handler presets, command planning/commands
selectors/Internal selector helpers (@internal-tagged)/selectors
koota/createWorld + per-tile/per-actor spawn helpers/koota
runtime/Runtime facade for snapshots + asset-root resolution/runtime
systems/Per-tick system functions (movement, patrol, quests, rules)/systems, /world-rules
simulation/Scripted scenario simulation engine/simulation
interop/Neutral ECS snapshot, external asset compatibility, release-readiness coverage/interop, /compatibility, /coverage
react/React bindings: provider, hooks, selectors/react
three/three.js bindings: loaders, scene helpers, animation/three
cli/The declarative-hex-worlds Node binary/cli
errors/7-class taxonomy: GameboardError + 6 subclasses/errors

The runtime is built on koota. koota’s discipline:

  1. Traits (traits/) declare the data — pure data, no behavior.
  2. Systems (systems/) read traits, decide what to do, mutate traits. Pure functions over world.
  3. Actions (the *Actions exports in each domain) are the bundled mutations consumers call.
  4. Selectors / Queries read traits without mutation.

The library follows that discipline strictly. src/traits/ exports every trait declaration in one barrel so cross-package trait identity stays stable (PRD invariant §6: splitting: true + trait identity test E4 pin this).

tsup builds with splitting: true so each subpath in package.json#exports becomes its own chunk. Trait identity survives across chunks (E4 tests it). sideEffects: false is on so consumers tree-shake aggressively.

The pipeline runs tsc --noEmit for typechecking, then tsup for both JS + DTS bundling. The two-pass approach (instead of tsup --dts only) keeps cycle-detection separate from bundling.

Per PRD §Phase RB, the library is bootstrap-not-bundle:

  • The published tarball ships only assets/free/manifest.json (the metadata).
  • The actual GLTF tree is fetched at install time by pnpm exec declarative-hex-worlds bootstrap.
  • The bootstrap-target lives under <consumer-out>/addons/kaykit_medieval_hexagon_pack/Assets/gltf/.
  • A .bootstrap.json integrity sidecar records per-file SHA256 + library version + source URL.

See the asset bootstrap guide for usage and the bootstrap layout reference for the upstream tree spec.

docs/PRD/1.0.md in the repo holds the rationale for every architectural choice. .agent-state/directive.md holds the work queue. Both are tracked in git; if you see a layout decision that’s confusing, check the PRD for the why.