Valenar WorldData Export Contract
This document describes what mapv10 stage 15 (valenar-worlddata) emits: the file pair, the schema-enforced field shapes, the units and ranges of every record type, the anchor records, the coordinate convention, the content-hash construction, and the schema-plus-imperative validator. It is reference material — the algorithmic internals (sample aggregation, area seeding, fact derivation) live in ./generator.md under Stage Reference / Stage 15.
These schemas are owned by mapv10 and live under examples/map/mapv10/schema/. The valenar prefix in filenames and format strings reflects the original consumer of this projection lane; mapv10 emits the contract regardless of who reads it.
For broader context, see ../architecture.md §Generator Pipeline and §Valenar WorldData Export. For the underlying artifact taxonomy these files coexist with, see §Artifact Contract And Schema in the same document.
Output Files
Stage 15 writes two JSON files into the run directory:
<run-dir>/valenar/world-{seed}.json— the world document.<run-dir>/valenar/world-{seed}.mesh.json— the companion mesh manifest.
Both filenames are derived from the run seed by world_file_name(seed) and mesh_file_name(seed) (generator/src/stages/valenar_worlddata.rs). The product paths under the run directory are valenar/<filename>, produced by world_product_path and mesh_product_path (see generator/src/stages/valenar_worlddata.rs) .
The two files reference each other by basename:
- The world document carries
mesh_artifact: "world-{seed}.mesh.json". - The mesh manifest carries
source_world: "world-{seed}.json".
Both are registered as products in the run manifest (generator/src/pipeline.rs):
| Product key | Schema id | Product type | Path |
|---|---|---|---|
valenarWorld | valenar-world-v1 | valenar-world-json | valenar/world-{seed}.json |
valenarWorldMesh | valenar-world-mesh-v1 | mesh-manifest-json | valenar/world-{seed}.mesh.json |
These two files sit alongside the rest of the native artifact set (mapv10 manifest, stage index, tile pyramid, mesh family manifests, previews, validation reports). They do not replace any native artifact. The full artifact taxonomy is documented in ../architecture.md §Artifact Contract And Schema.
The path strings inside the mesh manifest are run-relative — relative to the valenar/ directory itself. A consumer that reads valenar/world-{seed}.mesh.json and follows artifacts.mapv10_manifest = "../manifest.json" lands on the run-root manifest.json. This means the valenar/ subdirectory is not a self-contained payload: the mesh manifest assumes the rest of the mapv10 run remains at its sibling locations.
Canonical fixture sizes from the committed continent-lod6 run, examples/map/mapv10/viewer/public/continent-lod6/valenar/:
world-20260502.json— 12,971,820 bytes (~12.4 MiB).world-20260502.mesh.json— 655 bytes.
The world document carries the bulk of the payload (per-location polygons, facts, and the realm/area/province/location/anchor hierarchy). The mesh manifest is a thin pointer table to mesh and preview artifacts elsewhere in the run.
Format Constants
Three literal constants govern format identification (generator/src/stages/valenar_worlddata.rs):
FORMAT_VERSION: i32 = 1
WORLD_FORMAT: &str = "valenar_world"
MESH_FORMAT: &str = "valenar_world_mesh"
The schemas pin each constant with a JSON Schema const:
valenar-world.schema.json—"format": { "const": "valenar_world" },"format_version": { "const": 1 }.valenar-world-mesh.schema.json—"format": { "const": "valenar_world_mesh" },"format_version": { "const": 1 }.
Only format_version: 1 is defined. Consumers reject documents with any other value.
The two format discriminators serve a different purpose from format_version: they identify which document is being read (world vs. mesh manifest), not which schema generation it conforms to. A consumer that switches on format to dispatch to different parsers can ignore the separate-but-identical format_version constants.
World Document Schema
Schema id valenar-world-v1, file examples/map/mapv10/schema/valenar-world.schema.json. The root object is closed (additionalProperties: false) and all top-level fields are required.
| Field | Rust type | Schema constraint | Role |
|---|---|---|---|
format | String | const "valenar_world" | Discriminator; identifies this as a world document. |
format_version | i32 | const 1 | Schema major version; only 1 is defined. |
seed | i32 | integer | Run seed echoed back; the i32 projection of config.seed (see generator/src/stages/valenar_worlddata.rs) . |
generation_version | String | string, minLength: 1 | mapv10-generator/<GENERATOR_VERSION> (see generator/src/stages/valenar_worlddata.rs) . |
content_hash | String | ^sha256:[0-9a-f]{64}$ | SHA-256 over the world (with content_hash empty) plus the mesh document's scalar fields. See §Content Hash. |
mesh_artifact | String | ^world-[0-9]+\.mesh\.json$ | Sibling mesh manifest filename. |
world_bounds | ValenarWorldBounds | object | Continent-scale extent of the run. |
regions | Vec<ValenarWorldRegion> | minItems: 1 | Top-level realm/region records. |
areas | Vec<ValenarWorldArea> | minItems: 1 | Synthetic mid-tier groupings. |
provinces | Vec<ValenarWorldProvince> | minItems: 1 | Province-tier records. |
locations | Vec<ValenarWorldLocation> | minItems: 1 | Strategic-Location records with polygons and facts. |
anchors | Vec<ValenarWorldAnchor> | array | Starting Location and forced-feature anchors. |
Field shapes derive from ValenarWorldDocument in generator/src/stages/valenar_worlddata.rs and the root schema in valenar-world.schema.json.
world_bounds (schema valenar-world.schema.json):
| Sub-field | Type | Range | Role |
|---|---|---|---|
width_km | f64 | > 0 | Continent width along the X axis, derived from bounds.max_x - bounds.min_x and rounded to 4 decimals (see generator/src/stages/valenar_worlddata.rs) . |
height_km | f64 | > 0 | Continent height along the Y axis (see generator/src/stages/valenar_worlddata.rs) . |
preview_pixels | i32 | >= 1 | Maximum of config.raster_width and config.raster_height (see generator/src/stages/valenar_worlddata.rs) . |
content_hash is a literal sha256: prefix followed by 64 lowercase hex characters (no separators). mesh_artifact matches the regex ^world-[0-9]+\.mesh\.json$.
Mesh Manifest Schema
Schema id valenar-world-mesh-v1, file examples/map/mapv10/schema/valenar-world-mesh.schema.json. The root object is closed and all six top-level fields are required.
| Field | Rust type | Schema constraint | Role |
|---|---|---|---|
format | String | const "valenar_world_mesh" | Discriminator. |
format_version | i32 | const 1 | Schema major version. |
content_hash | String | ^sha256:[0-9a-f]{64}$ | Identical to the world document's content_hash; equality is asserted internally (see generator/src/stages/valenar_worlddata.rs) and externally. |
coordinate_system | String | const "mapv10_world_km_xy_y_down" | Coordinate convention for all geometry referenced by artifacts. See §Coordinate Convention. |
source_world | String | ^world-[0-9]+\.json$ | Sibling world document filename. |
artifacts | BTreeMap<String, String> | object | Path table to mesh and preview artifacts. |
Field shapes derive from ValenarWorldMeshDocument in generator/src/stages/valenar_worlddata.rs and the root schema in valenar-world-mesh.schema.json.
artifacts requires six keys and accepts one optional key (see the mesh schema artifacts definition). The path values are run-relative — relative to the valenar/ directory itself, so .. walks up to the run root. Values are produced by mesh_artifacts() (see generator/src/stages/valenar_worlddata.rs) :
| Key | Optional | Path |
|---|---|---|
mapv10_manifest | required | ../manifest.json |
mesh_manifest | required | ../meshes/mesh-manifest.json |
terrain_mesh_manifest | required | ../meshes/terrain-meshes.json |
water_mesh_manifest | required | ../meshes/water-meshes.json |
route_mesh_manifest | required | ../meshes/route-ribbons.json |
preview | required | ../previews/political-preview.png |
political_preview | optional (currently emitted) | ../previews/political-preview.png |
The schema's additionalProperties: { "$ref": "#/$defs/path" } (mesh schema the referenced source location) permits extra string-valued artifact keys. Consumers reading unknown keys must treat them as run-relative path strings.
Record Types
Region
| Field | Type | Role |
|---|---|---|
cell_id | i64 (schema id, >= 1) | Stable id derived from the realm's mapv10 numeric_id (see generator/src/stages/valenar_worlddata.rs) . |
name | String (minLength: 1) | Realm name. |
color | [i32; 3] (RGB 0-255) | Average color over child provinces, falling back to a hashed color (see generator/src/stages/valenar_worlddata.rs) . |
centroid | [f64; 2] | Mean of child-area centroids in km, falling back to the realm's label anchor (see generator/src/stages/valenar_worlddata.rs) . |
Regions are sorted by cell_id ascending (see generator/src/stages/valenar_worlddata.rs) . Region cell_id values use the realm's mapv10 numeric_id directly — the schema enforces >= 1, so realm numeric_id allocation must avoid zero. The schema places no upper bound on the realm numeric_id other than i64 storage.
Area
| Field | Type | Role |
|---|---|---|
cell_id | i64 | Synthetic id 200_000 + realm_index * 10_000 + local_index + 1 (see generator/src/stages/valenar_worlddata.rs) . |
region_cell_id | i64 | Owning realm's numeric_id. |
name | String | "<RealmName> Area NN" where NN is local_index + 1 zero-padded (see generator/src/stages/valenar_worlddata.rs) . |
color | [i32; 3] | Average color over child provinces (see generator/src/stages/valenar_worlddata.rs) . |
centroid | [f64; 2] | Mean of child-province label anchors in km (see generator/src/stages/valenar_worlddata.rs) . |
Areas are synthetic — they are not a mapv10 native concept. They are computed by farthest-first seeding of ceil(sqrt(province_count)) centers per realm, then assigning each province to its nearest center (see generator/src/stages/valenar_worlddata.rs) . For the algorithm, see ./generator.md §Stage 15.
Two consequences of the area-id formula matter for consumers:
- Area ids never collide with region or province ids. Regions and provinces use mapv10
numeric_idvalues (which are below200_000in any committed run); areas live in the200_000+band. - Each realm reserves a 10,000-id slot. With more than 10,000 areas in a single realm, the formula would alias into the next realm's slot. No committed scenario approaches this density, so the slot size is effectively a static guard rather than a tuning constant.
Areas are sorted by cell_id ascending (see generator/src/stages/valenar_worlddata.rs) .
Province
| Field | Type | Role |
|---|---|---|
cell_id | i64 | Province's mapv10 numeric_id. |
area_cell_id | i64 | Owning area's synthetic id. |
name | String | Province name. |
color | [i32; 3] | Average color over child locations, falling back to a hashed color (see generator/src/stages/valenar_worlddata.rs) . |
centroid | [f64; 2] | Province label anchor in km (see generator/src/stages/valenar_worlddata.rs) . |
neighbor_province_cell_ids | Vec<i64> | Symmetric adjacency. The export validator and the internal validator both check symmetry (see generator/src/stages/valenar_worlddata.rs) . |
is_coastal | 0 or 1 | 1 iff any child Location has is_coastal == 1 (see generator/src/stages/valenar_worlddata.rs) . |
primary_biome | String | Modal biome over child locations, excluding "sea" and "freshwater", falling back to "plains" (see generator/src/stages/valenar_worlddata.rs) . |
Provinces are sorted by cell_id ascending (see generator/src/stages/valenar_worlddata.rs) .
The primary_biome exclusion of "sea" and "freshwater" ensures that provinces with shoreline or lakeshore Locations report a meaningful land-biome label even if water Locations dominate the count. A province with only sea/freshwater children falls back to "plains" (see generator/src/stages/valenar_worlddata.rs) .
Location
| Field | Type | Role |
|---|---|---|
cell_id | i64 | Location's mapv10 numeric_id. |
province_cell_id | i64 | Owning province's numeric_id. |
name | String | Location name. |
centroid | [f64; 2] | Location label anchor in km (see generator/src/stages/valenar_worlddata.rs) . |
polygon | Vec<[f64; 2]> | Location polygon in km, minItems: 3, with each coordinate rounded to 4 decimals (see generator/src/stages/valenar_worlddata.rs) . |
color | [i32; 3] | Color from province_color_seeds, falling back to a hashed color (see generator/src/stages/valenar_worlddata.rs) . |
biome | String | One of "sea", "plains", "forest", "highlands", "snow", "freshwater", "wetland" (see generator/src/stages/valenar_worlddata.rs) . |
is_water | 0 or 1 | 1 iff strictly more than half of raster samples within the Location are water (see generator/src/stages/valenar_worlddata.rs) . |
is_coastal | 0 or 1 | 1 iff any sea sample is present, or water_coverage (in 0..100) is at least 8 (see generator/src/stages/valenar_worlddata.rs) . |
neighbor_cell_ids | Vec<i64> | Symmetric adjacency over the location-kind subgraph of the neighbor graph (see generator/src/stages/valenar_worlddata.rs) . |
facts | ValenarWorldLocationFacts | See below. |
Locations are sorted by cell_id ascending (see generator/src/stages/valenar_worlddata.rs) .
Two boundary rules to note:
is_wateris a strict majority test on raster samples (channels.water_samples > channels.sample_count / 2). A Location with exactly half water samples emitsis_water: 0.is_coastalcovers two distinct cases: any sea-touching sample (sea adjacency on the open ocean) or a freshwater fraction of at least 8% (lake/river coastline). A Location can be bothis_water: 1andis_coastal: 0only if its water samples are entirely freshwater and below the 8% threshold — an edge case in practice.
LocationFacts
Every fact is an integer. Nine of the ten facts are normalized to 0..=100 and serialized through the pct clamp helper. The tenth, elevation, is integer metres and uses a separate code path. Facts are computed once per Location during generate and embedded inline in each ValenarWorldLocation; they are not stored separately.
Each fact is a normalized integer with the range and derivation listed below. All values except elevation are 0..=100.
| Field | Range | Derivation source |
|---|---|---|
fertility | 0..=100 | biome_fertility + forest_pct * 0.18 + wetland_pct * 0.20 - water_pct * 0.30 - slope * 8.0, clamped (see generator/src/stages/valenar_worlddata.rs) . |
forest_coverage | 0..=100 | Mean biomes.forest_mask over Location samples scaled from 0..255 to 0..100 (see generator/src/stages/valenar_worlddata.rs) . |
water_coverage | 0..=100 | Fraction of Location samples flagged as water, scaled to 0..100 (see generator/src/stages/valenar_worlddata.rs) . |
mineral_wealth | 0..=100 | highland_bias * 0.42 + slope * 12 + (biome == highlands) * 20 + noise_a * 8, clamped (see generator/src/stages/valenar_worlddata.rs) . |
elevation | >= 0 (integer metres) | Mean heightfield.height over Location samples, rounded to integer metres (see generator/src/stages/valenar_worlddata.rs) . |
base_threat | 0..=100 | 16 + slope * 11 + mineral * 0.14 + ancient * 0.16 + corruption * 0.20 - route * 0.10 + noise * 18, clamped (see generator/src/stages/valenar_worlddata.rs) . |
ancientness | 0..=100 | Position-weighted seed plus mineral * 0.18 + route * 0.12 + noise_b * 18 + 28, clamped (see generator/src/stages/valenar_worlddata.rs) . |
route_importance | 0..=100 | Maximum incident edge importance from routes.location_connection_graph, scaled to 0..100 (see generator/src/stages/valenar_worlddata.rs) . |
corruption | 0..=100 | ancient * 0.22 + water * 0.08 + (1 - route_importance) * 18 + noise * 28, clamped (see generator/src/stages/valenar_worlddata.rs) . |
settlement_suitability | 0..=100 | fertility * 0.48 + route * 0.22 + mineral * 0.12 + (water in (0,35)) * 6 - threat * 0.20 - corruption * 0.18 + 22, clamped (see generator/src/stages/valenar_worlddata.rs) . |
Note: elevation is the only fact field in metres rather than 0..=100; treating it uniformly with the other facts will misread high-altitude locations.
The clamp helper pct(value) rounds and clips to 0..=100 (see generator/src/stages/valenar_worlddata.rs) ; elevation skips pct and uses round() as i32 directly (see generator/src/stages/valenar_worlddata.rs) .
Anchor Records
Each anchor is a three-field struct (ValenarWorldAnchor in generator/src/stages/valenar_worlddata.rs, schema valenar-world.schema.json):
| Field | Type | Role |
|---|---|---|
kind | String (enum: ["starting_location", "forced_feature"]) | Anchor category. |
location_cell_id | i64 | Target Location's cell_id. |
template | String (minLength: 1) | Template name as a bare string literal. |
There are two anchor kinds (see generator/src/stages/valenar_worlddata.rs) :
| Kind | Count | Templates |
|---|---|---|
starting_location | exactly 1 | "BareLocation" |
forced_feature | at least 4 | "DormantNexus", "Ruins", "OreVein", "MysticGrove", "AbandonedFortress" |
The starting Location and the DormantNexus forced feature share the same location_cell_id. The remaining four forced features select distinct Locations from the land-only candidate set, each scored by a weighted expression over the Location's facts (see generator/src/stages/valenar_worlddata.rs) . For the exact scoring expressions, see ./generator.md §Stage 15.
Template names are emitted as bare string literals. mapv10 does not validate that a template name corresponds to a real entry in any consumer's asset registry; that is the consumer's responsibility.
Coordinate Convention
The mesh manifest carries a coordinate_system literal that pins the convention for both files (generate in generator/src/stages/valenar_worlddata.rs, schema valenar-world-mesh.schema.json):
"coordinate_system": "mapv10_world_km_xy_y_down"
Reading the label component by component:
mapv10_world— the native mapv10 generator coordinate space; no projection or transform.km— units are kilometres forcentroid(regions, areas, provinces, locations) andpolygon(locations).xy_y_down— X axis east, Y axis south. The origin is at the northwest corner ofworld_bounds.
The single exception to "everything is km" is facts.elevation, which is in integer metres. Everything else linear is in kilometres.
Numeric precision: centroid and polygon values are rounded to four decimal places via round4 (see generator/src/stages/valenar_worlddata.rs) , giving 0.1-metre resolution at km scale.
A consumer rendering at sub-metre precision must accept the 0.1-metre quantization as the floor; recovering finer geometry from this contract is impossible. A consumer projecting to a different convention (Y-up, metres, or non-zero origin) is responsible for its own transform — mapv10 emits the data in km/Y-down/origin-NW only.
For the broader unit system across the generator, see ../architecture.md §Coordinate System And Units.
Content Hash
Algorithm: SHA-256, via the sha2 = "0.10" crate (generator/Cargo.toml).
Input: a serialized HashInput struct in generator/src/stages/valenar_worlddata.rs defined as the world document with its own content_hash field set to the empty string, joined with the mesh manifest's scalar/path fields (format, format version, coordinate system, source-world basename, and the artifacts path table). The referenced mesh binary bytes are not read and are not part of this structural hash:
struct HashInput<'a> {
world: &'a ValenarWorldDocument, // content_hash = ""
mesh_format: &'a str, // "valenar_world_mesh"
mesh_format_version: i32, // 1
mesh_coordinate_system: &'a str, // "mapv10_world_km_xy_y_down"
mesh_source_world: &'a str, // "world-{seed}.json"
mesh_artifacts: &'a BTreeMap<String, String>,
}
This shape exists because the world's content_hash and the mesh's content_hash must end up equal — hashing either document literally would create a circular dependency. By zeroing the world's hash and folding only the mesh manifest's non-hash scalar/path fields into the input, both documents can be stamped with the same digest after a single hash pass.
Output: sha256:<64 lowercase hex>. The hex emitter is hex_lower (see generator/src/stages/valenar_worlddata.rs) , the format string is format!("sha256:{}", hex_lower(&digest)) (see generator/src/stages/valenar_worlddata.rs) .
The same hash is written into both files. Equality is asserted by:
- The internal validator (
validate_exportingenerator/src/stages/valenar_worlddata.rs, thecontent-hashcheck in the stage validation report). - The external validator at
viewer/scripts/validate-valenar-export.mjs.
What the hash does NOT cover: the binary mesh files referenced in artifacts paths. The hash protects only the structural world JSON plus mesh-manifest scalar/path tuple; the bytes those paths point at are outside the contract.
Practical implication: two runs that produce identical world+mesh JSON but different mesh binary content (an impossibility under the determinism contract, but useful as a worked example) would carry the same content_hash. Conversely, any change to the world document — a renamed Location, a different forced_feature template, a shifted polygon — changes the hash, and mapv10 stamps the new hash into both files. A consumer using content_hash as a cache key sees the right invalidation behavior for everything inside the JSON pair, and no signal at all for the binary artifacts.
Determinism
Same seed plus same GeneratorConfig produces byte-identical world-{seed}.json and world-{seed}.mesh.json.
The determinism test same_config_produces_same_core_product_bytes (generator/src/pipeline.rs) runs the full pipeline twice with the same config and asserts byte equality on a closed product list:
for key in [
"config",
"height",
"slope",
"normal",
"sediment",
"flowAccumulation",
"valenarWorld",
"valenarWorldMesh",
] {
...
assert_eq!(first_bytes, second_bytes, "{key} bytes drifted");
}
Mechanism:
BTreeMap<String, String>forartifactsorders keys lexicographically, so JSON output is canonical.- Region, area, province, and Location lists are explicitly sorted by
cell_idafter construction (seegenerator/src/stages/valenar_worlddata.rs) . serde_json::to_vecemits canonical UTF-8 JSON with no random whitespace.Sha256::digestis deterministic by definition.
For the broader generator-side determinism story (PRNG splitting, stage isolation, no-clock policy), see ./generator.md §Determinism Contract.
The export-side determinism story is narrower: it adds canonical sort orders for the four hierarchy lists (regions, areas, provinces, locations) and depends on BTreeMap ordering for the mesh artifacts table. Anchor order is defined by construction order in build_anchors (see generator/src/stages/valenar_worlddata.rs) — starting Location first, then DormantNexus, then Ruins, OreVein, MysticGrove, AbandonedFortress in that fixed sequence. The order is part of the contract; consumers may rely on it.
Validator: validate-valenar-export.mjs
Location: examples/map/mapv10/viewer/scripts/validate-valenar-export.mjs. Entry point: the exported validateValenarExport(runRoot) function at the referenced source location.
CLI invocation:
node scripts/validate-valenar-export.mjs [--run-root <dir>] [--json]
Default --run-root is <viewer>/public/continent-lod6 (see validateValenarExport). The --json flag emits the full summary object (including any errors) as JSON instead of the human-readable summary.
npm script (viewer/package.json):
"validate:valenar-export": "node scripts/validate-valenar-export.mjs --run-root public/continent-lod6"
The validator first runs strict draft 2020-12 JSON Schema validation against schema/valenar-world.schema.json and schema/valenar-world-mesh.schema.json, then runs the existing imperative cross-document checks. Schema validation owns closed object shapes, required fields, primitive ranges, tuple lengths, and enum/const constraints; the imperative pass still owns manifest registration, stage status, file-pair equality, reference resolution, neighbor symmetry, and required artifact-key presence.
Check categories:
- Manifest existence —
manifest.jsonandstage-index.jsonmust exist inrunRoot. Missing files throw rather than appending toerrors. - Manifest products —
valenarWorldandvalenarWorldMeshentries must be present inmanifest.products. - Stage index status — stage
valenar-worlddatamust exist instage-index.stagesand have statuspass. - Manifest validation status —
manifest.validationStatusmust be"pass". - Product type and schema —
valenarWorldmust haveproductType: "valenar-world-json"andschema: "valenar-world-v1";valenarWorldMeshmust haveschema: "valenar-world-mesh-v1". - File existence — both world and mesh files must exist on disk.
- JSON Schema validation — the world and mesh documents must satisfy their strict mapv10 schemas before cross-document checks run.
- Top-level shape —
worldandmeshmust be objects;regions,areas,provinces,locations,anchorsmust be arrays. - Format constants —
world.format == "valenar_world",world.format_version == 1,mesh.format == "valenar_world_mesh",mesh.format_version == 1. - Content hash format and equality —
world.content_hashmatches^sha256:[0-9a-f]{64}$and equalsmesh.content_hash. - Cross-references between files —
mesh.source_worldmatches the world filename,world.mesh_artifactmatches the mesh filename. - Hierarchy non-emptiness and anchor counts — at least one region, area, province, Location; at least one
starting_locationanchor; at least fourforced_featureanchors. - Reference resolution — every
area.region_cell_id,province.area_cell_id,location.province_cell_id, andanchor.location_cell_idresolves to an existing record. - Symmetric neighbors — every province in
neighbor_province_cell_idslists the back-edge; every Location inneighbor_cell_idslists the back-edge. - Mesh artifacts table — six required keys (
mapv10_manifest,mesh_manifest,preview,terrain_mesh_manifest,water_mesh_manifest,route_mesh_manifest) must be present inmesh.artifacts.
Return value: a summary object containing runId, seed, scalePreset, validationStatus, stage status, hierarchy counts, contentHash, byte sizes (run total + each file), product paths, and an errors list (see validateValenarExport). The CLI exits non-zero when errors.length > 0 (see validateValenarExport). The validator does not compute or report file-byte digests; content_hash is the only Valenar export identity hash and keeps its structural gameplay JSON plus mesh-manifest scalar/path semantics.
Out of Scope
The following items are outside the export contract — mapv10 does not enforce them, and a passing world+mesh document carries no commitment about them:
- Consumer behavior. What a consumer does with the data — how it indexes Locations, how it surfaces anchors, how it interprets templates — is not part of this contract.
- Consumer-side parse and load performance. Document size and shape are documented in §Output Files; runtime performance characteristics on any specific consumer are not.
- Starting-location-on-land guarantee. The starting Location is preferred to be on land, but
build_anchorsfalls back to any Location if no land Locations exist (seegenerator/src/stages/valenar_worlddata.rs) . On a fully-water world, the starting Location can be a water Location. - Anchor template registry membership. Template names are bare string literals (see §Anchor Records). Validating that
"DormantNexus","Ruins", etc. exist in any consumer's asset registry is downstream work. - Binary mesh file integrity. The paths under
mesh.artifactspoint at terrain, water, and route mesh files outside the JSON contract. Their byte content is not covered bycontent_hash(see §Content Hash). - Schema migration.
format_version: 1is the only defined version (see §Format Constants). No upgrade path is defined. - Cross-run product identity. Two runs with the same seed and config produce byte-identical files (see §Determinism), but seed-config equivalence is the only identity relation guaranteed. Two runs with different configs that happen to produce structurally similar worlds carry different
content_hashvalues and are not equivalent under this contract. - Anchor template extension. The committed forced-feature template list (
DormantNexus,Ruins,OreVein,MysticGrove,AbandonedFortress) is fixed inbuild_anchors. Adding a new template requires a generator change.
Source / Symbol Map
Pointer table for the cited source locations:
| Topic | Path | Symbol / section |
|---|---|---|
| Format constants | generator/src/stages/valenar_worlddata.rs | format constants |
| World struct | generator/src/stages/valenar_worlddata.rs | ValenarWorldDocument |
| Mesh manifest struct | generator/src/stages/valenar_worlddata.rs | ValenarWorldMeshDocument |
| Anchor struct | generator/src/stages/valenar_worlddata.rs | ValenarWorldAnchor |
| File-name helpers | generator/src/stages/valenar_worlddata.rs | file-name and product-path helpers |
generate entry point | generator/src/stages/valenar_worlddata.rs | generate |
| Internal validator | generator/src/stages/valenar_worlddata.rs | validate_export |
| Area seeding | generator/src/stages/valenar_worlddata.rs | area seeding helpers |
| Fact derivation | generator/src/stages/valenar_worlddata.rs | location fact derivation |
| Anchor builder | generator/src/stages/valenar_worlddata.rs | build_anchors |
| Mesh artifacts table | generator/src/stages/valenar_worlddata.rs | mesh_artifacts |
| Content hash | generator/src/stages/valenar_worlddata.rs | compute_content_hash |
| World schema | schema/valenar-world.schema.json | root schema and $defs |
| Mesh manifest schema | schema/valenar-world-mesh.schema.json | root mesh schema and $defs |
| Pipeline product registration | generator/src/pipeline.rs | stage 15 product registration |
| Determinism test | generator/src/pipeline.rs | same_config_produces_same_core_product_bytes |
| External validator | viewer/scripts/validate-valenar-export.mjs | validateValenarExport and CLI entry |
sha2 crate version | generator/Cargo.toml | sha2 dependency declaration |
For navigating the rest of the docs surface, see ../architecture.md, ./generator.md, ../wave-protocol.md, ../scenarios.md, and ../extending.md.