The Cyberia content: the foundation, the instances, the sagas, the semantic generator and the versioned content artifact the engine consumes.
This repository creates content. The engine imports, materializes, releases and deploys it.
cyberia-content ──validate──► build ──► dist/ (the content artifact: data and its manifest)
│
engine: this checkout (CYBERIA_CONTENT_ROOT) or a packed copy of it
│
cyberia instance --import · content import · content-release
| Path | Holds |
|---|---|
src/content/foundation/ |
The functional blueprint: world, environment, items, characters, maps, quests, actions |
src/content/instances/ |
Instance backups, one directory per instance code, as the engine exports it |
src/content/global/ |
Global content: one Object Layer definition per CID that no world carries |
src/content/sagas/ |
Saga packages, one file per saga code |
src/content/procedural/ |
Genesis Templates and global palettes: where a procedural generation starts |
src/schema/ |
The definition schema and the runtime contract (generated by the engine) |
src/validation/ |
Content rules and the canonical JSON form |
src/procedural.js |
Reads the procedural templates and checks them against the foundation |
src/compiler.js |
Definitions to runtime documents: one list per document family |
src/generator/ |
Semantic generation: prompts, stages, the saga package, the Gemini client |
src/packaging/ |
The artifact: build, manifest and digests |
npm install
node bin/cyberia-content.js <command>| Command | Does |
|---|---|
validate [--fix] |
Validate canonical form, foundation, sagas and instances; --fix rewrites form |
saga generate |
Compose a saga with Google Gemini and write its package |
saga step --state <file> |
Run the next step of a stored generation and write the state back |
saga check --file <file> [--write] |
Print JSON: the findings of a package, its runtime documents and its context |
saga instance <saga-code> [--force] [--dry-run] |
Write the instance backup of a saga |
build |
Write dist/ from the committed content |
pack |
Build and pack artifacts/cyberia-content-<version>.tgz |
--env-file <path> reads the environment from a file. ./.env is read when it exists.
cyberia-content.config.js configures this checkout. Every command and test reads it.
| Field | Holds |
|---|---|
ignoreSagas |
Saga codes every process skips, as if their package does not exist. dist/ omits them |
Remove a saga code from ignoreSagas when its package is valid.
The foundation defines what exists and how it functions. Studio adds only how it looks (render) and where it is (placement).
A definition id is <kind>.<slug>, for example biome.violet-strata. One JSON file holds one
definition, at <category>/<id>.json. Every definition has a name, a description and a role.
| Kinds | Define |
|---|---|
region, biome, faction, origin, material |
The world. Only the foundation defines them |
floor, tree, vegetation, rock, prop, structure, ruin, portal |
Environment: each one is an Object Layer item and an entity |
weapon, armor, skin, projectile, currency, resource, consumable, relic, technology, implant, tool |
Carried items |
character |
Loadout, carried items, the spawned entity and a greeting |
ability, effect |
What items do: a runtime skill handler and its effects |
map |
A place of one biome, and its composition: each entity and how many |
quest |
Provider, steps, objectives, rewards, talk, prerequisites and unlocks |
action |
What a provider offers: shop, recipes, storage, buyback, burn, market |
An item or environment definition carries an objectLayer block: the item type, the activable
flag and the stats. Its item label is its slug. Its artBrief tells an artist what to draw. It holds
no pixels, frames, atlases or CIDs.
A consumable heals its resistance stat as life and carries no other stat. An ability with the
zero-waste-auto-consume-heal logic lets its holder consume one unit by itself, once the missing
life takes the whole heal. The ability names no summons: it summons the consumable that carries
it, and only a consumable may carry it. Its optional loot names the pickup behavior of the item as
world loot (consume-on-pickup-heal); the compiler writes it as a loot entity-type default.
Without it, a world pickup of the item grants it.
A biome carries a palette: #rrggbb colors by role (base, shadow, highlight, outline,
and optionally accent and special). The Studio paints with it; it is guidance, never render.
A map composes entities its biome holds. The compiled map holds none: Studio places each one and tracks the composition against the context index. A quest provider and each talk target stand behind an action of the same set.
The runtime gates a quest by its prerequisites alone. A quest that unlocks another is one of its
prerequisites, a prerequisite of the same set unlocks the quest it gates, and no chain of
prerequisites loops. A kill objective targets a character that spawns as a bot.
An action has no type: its capabilities are the fields it fills, and it may combine several. A
market terminal names a market of the foundation; the market owns the shared terms. The economy
item policy still decides what a buyback, a burn or a listing may take.
foundation.json holds the schemaVersion of the definition format and the baseline: the
definition each runtime entity type resolves against when a world authors none (entities), and
the item whose activable flag and stats a new item of each type starts from (items).
The engine generates candidate renders from these templates. They are where a generation starts, never a render, and they define no item.
A Genesis Template, procedural/genesis-templates/<itemType>.<slug>.json, is a reusable visual
start for one item type:
| Field | Holds |
|---|---|
canvas |
Width and height in cells |
directions |
One region map per direction code: one string per row, one letter per cell |
legend |
The region id each letter marks; . marks no region |
roles |
The roles: the regions, the palette role and the shadow, base, highlight tones |
outline |
The outline color |
frameDurationMs |
The frame duration of a render that starts from the template |
A role with artDirection takes the colors the art direction of an item names. Each role names the
palette role it takes in palette: primary, secondary, detail or feature.
A palette, procedural/palettes/<slug>.json, is one theme of one global library. It belongs to no
item type. It gives a color to primary and outline, and to any of secondary, detail,
feature and accent the theme needs. Every palette colors every Genesis Template: a role takes the
color of its palette role, and a role whose palette role the palette does not give keeps its
default. A palette has a unique name, a family, the foundation biomes it suits (biomeTags, by
slug) and its constraints: the least OKLab distance between the outline and the contrastRoles.
The engine derives the shadow and highlight of each role and checks the contrast.
| Palette role | Takes | Skin | Floor | Portal | Obstacle |
|---|---|---|---|---|---|
primary |
The main mass | torso | ground | swirl | chunk |
secondary |
The second mass | legs | patch | rim | loose |
detail |
Small dark parts and lines | hair | depth | seam | |
feature |
The distinct part | skin | core | dust |
A new item of a type takes its function from baseline.items, its look from a Genesis Template and
its colors from a palette. A human then finishes it in the Object Layer Studio.
src/compiler.js turns definitions into runtime documents, one list per family, in import order:
| Family | Documents |
|---|---|
object-layers |
One Object Layer item per labeled definition, without render |
entity-type-defaults |
One per entity definition: live, dead, drop and inventory items, behavior |
skills |
One per item whose abilities name a runtime handler |
maps |
One per map: code, name, description and biome tags; no entities |
quests |
Steps, objectives and rewards by item label; source map and cell null |
dialogues |
Item flavor text, character greetings and quest talk |
actions |
Shop, recipes, storage and quest talk codes; source map and cell null |
The same compiler compiles the foundation and each saga. It also derives the context index the Studio reads: every definition of the foundation and the sagas, its source, the item label and the map entity it answers to, and every reference in both directions with the field that makes it.
The generator composes a saga over the foundation. Gemini reuses foundation definitions and adds only what the saga lacks, in the definition model of the foundation.
theme (from --prompt, or synthesized from the lore)
│
▼
Google Gemini, six bounded stages, each one returning definitions
│ 1 composition → saga identity, the foundation ids it uses, new definitions
│ 2 maps → maps of foundation biomes, and what each one composes
│ 3 quests → quests over characters and items
│ 4 dialogues → greetings of new characters and the talk of quests
│ 5 actions → what each quest provider and talk target offers
│ 6 abilities → abilities of new items, reused or defined
▼
normalize → validate → src/content/sagas/<saga-code>.json
The composition stage reads a compact index of the foundation. Each later stage reads the full definitions of what the saga uses. The model follows these rules, and normalization enforces them:
- Reuse a foundation definition by its exact id. Never define a duplicate.
- Never define a region, biome, faction, origin or material.
- Use only the skill handlers of the runtime contract.
- Write no coordinates, cells, grids, portal endpoints, pixels, frames, atlases or CIDs.
An invalid package is written for a human to fix. The command then fails with its findings.
A generation is a JSON state that each step advances: the theme, each stage, then the package.
saga step --state <file> runs the next step and writes the state back; a step that fails leaves
the state as it was, and exit code 2 means the request cannot run. A step retries a timeout or a
quota answer, after the delay the answer names; a request the model refuses fails at once with exit
code 2. The engine stores the state after
each step, so a generation resumes where it stopped. The request of a state may fix the saga
identity (saga), name definitions the saga must use (reuse) and name the sagas whose definitions
it may reuse (sagas).
saga check --file <file> checks a package as validate would after it is written, against the
foundation and every other saga. It prints JSON: findings, and for a valid package compiled (the
runtime documents of the saga) and context (the context index entries of its definitions, of what
they name and of what names them). --write writes a valid package to its file in canonical form.
# A lore-grounded saga. The world foundation is the lore unless --lore-path names a document.
node bin/cyberia-content.js saga generate
# A given theme, validated but not written
node bin/cyberia-content.js saga generate --prompt "A relay keeper in the ash wastes" --dry-runGEMINI_API_KEY must be in the environment. Steer a synthesized theme with --space-context
(physical, mixed, hyperspace), --tone (adventure, politics, tragic, comedy),
--faction-context (foundation confederations that drive the saga, for example nova,zenith),
--character-context (name pools) and --cultural-exposure (cosmopolitan, local).
| Field | Holds |
|---|---|
schemaVersion |
Version of the package format |
foundationVersion |
The content version the saga was composed against |
saga |
code, name, description |
references |
Every id of the foundation or of another saga the definitions name |
places |
Optional: the maps of the foundation or of another saga it plays on |
definitions |
The new definitions, maps, quests and actions, in the foundation model |
The build compiles a package with the compiler of the foundation. The saga adds its own documents
of every family, its CyberiaSaga record and the shell of its instance.
A saga may use a definition of another saga by its id, as it uses a foundation one. It never defines it again: the saga that defines it compiles its documents. An id or an item label belongs to one source only.
A place is a map the saga uses and another source defines. The CyberiaSaga record names its own
maps in mapCodes and its places in placeCodes. The source that defines a place stays its owner:
the saga compiles no document of it, and its instance shell does not hold it. A quest or an action
whose provider stands on a place gets that map as its source map. Each place names a map of
another source, once.
saga instance <saga-code> writes src/content/instances/<saga-code>/ from the saga package
alone, in the layout of an engine instance export. The same package always writes the same bytes.
The engine imports it with cyberia instance <saga-code> --import.
| Holds | From |
|---|---|
| The instance and its conf | The saga code. The conf names every entity-type default of the backup |
| Maps | Every saga map, with no entities |
| Entity-type defaults | Every saga entity, and every foundation entity a saga map composes |
| Quests, actions | Every saga quest and action, with no source |
| Object Layer items | Every item the defaults, actions and quests name, or a skill summons; no render |
| Skills, dialogues, the saga | The skills of those items, their lines and the action talk, the CyberiaSaga |
The command refuses an instance directory that exists: it holds the render and placement of
Studio. --force replaces it. An engine export keeps only the quests and actions Studio placed.
An instance with object-layers/ is a complete snapshot: object-layers/<itemId>.json is the
definition the item ran when the engine exported it, and an import binds the item to it again.
Quests and actions name items by item id. In a snapshot, a quest or an action may also pin an item
(objectLayerCid), but only to the definition the snapshot binds it to. validate reports any
other pin.
src/schema/runtime-contract.json holds the runtime vocabulary content uses: item types, entity
types, stat bounds, skill handlers, quest step types, the item dialogue prefix and the dialogue
moods. The engine owns that vocabulary and generates the file with node bin/cyberia stat-contract.
Never edit it.
src/content/global/<cid>.json holds one Object Layer definition that Cyberia keeps with no world:
an import, an item binding no world carries, or stacks players own keep it. The engine writes these
files with cyberia content source export-live; never author them by hand. Each file holds:
| Field | Holds |
|---|---|
definition |
The canonical payload { schemaVersion, profile, data }; its bytes hash to the CID |
render |
null, or the layout and the primary render (base64) the definition names |
itemIds |
The item ids the catalog bound to it at export, sorted |
registration |
Why it stays (import, catalog or owned), who registered it, when and from where |
A global definition needs no entity-type default, map, saga or instance. Validation checks the structure; the engine checks the identity and the render when it imports the file.
The artifact is data: dist/ and its manifest. It holds no code; the consumer verifies it.
| Path | Holds |
|---|---|
dist/manifest.json |
Identity and the digest of every file |
dist/context.json |
The context index of the Studio |
dist/foundation/<family>.json |
The compiled foundation, one file per document family |
dist/foundation/baseline.json |
The entity-type defaults a world resolves against |
dist/foundation/item-baseline.json |
The item label a new item of each type takes its function from |
dist/procedural/genesis-templates.json |
Every Genesis Template |
dist/procedural/palettes.json |
The palette families, in order, and every global palette |
dist/sagas/<code>/<family>.json |
Each compiled saga, one file per document family |
dist/sagas/<code>/saga.json |
Its CyberiaSaga record |
dist/sagas/<code>/instance.json |
The shell of its instance |
dist/instances/<code>/ |
Each instance backup |
dist/global/<cid>.json |
Each global content definition |
The manifest names repository, contentVersion, sourceRevision, schemaVersion,
contentDigest, build, instances, sagas, global and files. The content digest is the sha256 of one
<path> <sha256> line per file, in path order. The same commit always builds the same bytes.
The engine reads the artifact of this checkout in development: run build after each commit.
pack writes the same artifact as artifacts/cyberia-content-<version>.tgz; the engine reads an
extracted copy the same way. A registry, an OCI image or a release asset can carry that tarball
later without a change to the artifact.
- Change content, run
validate, and commit. The build refuses uncommitted content. - Increment
versioninpackage.jsonand commit. A released version never changes. - Run
build. The engine reads the new artifact from this checkout. - In the engine,
cyberia release lockpins this revision and the artifact inunderpost.lock.jsonof the deployment: repository, revision, version and digest. - A deploy fetches that exact revision, builds it again with
npm ci,npm testandnpm pack, and fails unless the result matches the lock.
A source channel selects only the repository a deploy fetches the revision from: this repository,
or cyberia-content-private. A release from either channel is a production release. A deploy
never pushes to either repository.