@world-engines/spatial-authoring 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,317 @@
1
+ import { validatePlaneGeneration } from "./plane-generation.js";
2
+ import { validateProceduralWorld } from "./procedural-city.js";
3
+ import { validateRoadGeneration } from "./road-generation.js";
4
+ import { validateSpatialTemplateConfiguration, validateSpatialTemplateLibrary, } from "./spatial-templates.js";
5
+ const textEncoder = new TextEncoder();
6
+ const textDecoder = new TextDecoder("utf-8", { fatal: true });
7
+ const SPATIAL_KEY = /^[a-z][a-z0-9-]{0,63}$/;
8
+ function fail(message) { throw new TypeError(message); }
9
+ function record(value, label) {
10
+ if (typeof value !== "object" || value === null || Array.isArray(value))
11
+ fail(`${label} 必须是 object`);
12
+ return value;
13
+ }
14
+ function stringValue(value, label) {
15
+ if (typeof value !== "string" || value.trim().length === 0)
16
+ fail(`${label} 必须是非空 string`);
17
+ return value;
18
+ }
19
+ function finiteCoordinate(value, label) {
20
+ if (typeof value !== "number" || !Number.isFinite(value))
21
+ fail(`${label} 必须是有限数`);
22
+ return value;
23
+ }
24
+ function controlledActorId(value, label) {
25
+ if (value === undefined || value === null)
26
+ return value;
27
+ if (typeof value !== "string" || !/^[^\0\r\n]{1,512}$/u.test(value))
28
+ fail(`${label} 必须是有效 entity id 或 null`);
29
+ return value;
30
+ }
31
+ function spatialKind(value, label) {
32
+ if (value === "location" || value === "portal" || value === "region")
33
+ return value;
34
+ return fail(`${label} 不支持的 spatial kind`);
35
+ }
36
+ function stableJson(value) { return textEncoder.encode(JSON.stringify(value)); }
37
+ function compareCodepoint(left, right) {
38
+ const leftPoints = Array.from(left, (value) => value.codePointAt(0));
39
+ const rightPoints = Array.from(right, (value) => value.codePointAt(0));
40
+ const length = Math.min(leftPoints.length, rightPoints.length);
41
+ for (let index = 0; index < length; index += 1)
42
+ if (leftPoints[index] !== rightPoints[index])
43
+ return leftPoints[index] - rightPoints[index];
44
+ return leftPoints.length - rightPoints.length;
45
+ }
46
+ function stableStructuralJson(value) {
47
+ const normalize = (candidate) => {
48
+ if (Array.isArray(candidate))
49
+ return candidate.map(normalize);
50
+ if (candidate === null || typeof candidate !== "object")
51
+ return candidate;
52
+ return Object.fromEntries(Object.entries(candidate)
53
+ .filter(([, entry]) => entry !== undefined)
54
+ .sort(([left], [right]) => compareCodepoint(left, right))
55
+ .map(([key, entry]) => [key, normalize(entry)]));
56
+ };
57
+ return JSON.stringify(normalize(value));
58
+ }
59
+ function spatialObjectSignature(object) {
60
+ return stableStructuralJson({ id: object.id, key: object.key, kind: object.kind, label: object.label, x: object.x, y: object.y, references: object.references });
61
+ }
62
+ function bytesToBase64(bytes) {
63
+ let binary = "";
64
+ for (let offset = 0; offset < bytes.length; offset += 0x8000)
65
+ binary += String.fromCharCode(...bytes.subarray(offset, offset + 0x8000));
66
+ return btoa(binary);
67
+ }
68
+ function base64ToBytes(encoded) {
69
+ const binary = atob(encoded);
70
+ const bytes = new Uint8Array(binary.length);
71
+ for (let index = 0; index < binary.length; index += 1)
72
+ bytes[index] = binary.charCodeAt(index);
73
+ return bytes;
74
+ }
75
+ function readVarint(bytes, start) {
76
+ let value = 0;
77
+ let shift = 0;
78
+ for (let offset = start; offset < bytes.length && offset < start + 10; offset += 1) {
79
+ const byte = bytes[offset];
80
+ value += (byte & 0x7f) * 2 ** shift;
81
+ if ((byte & 0x80) === 0)
82
+ return { value, next: offset + 1 };
83
+ shift += 7;
84
+ }
85
+ return fail("Scenario protobuf varint 无效");
86
+ }
87
+ function varint(value) {
88
+ if (!Number.isSafeInteger(value) || value < 0)
89
+ fail("protobuf varint 必须为非负安全整数");
90
+ const out = [];
91
+ do {
92
+ const byte = value % 128;
93
+ value = Math.floor(value / 128);
94
+ out.push(value === 0 ? byte : byte | 0x80);
95
+ } while (value !== 0);
96
+ return new Uint8Array(out);
97
+ }
98
+ function concat(parts) {
99
+ const out = new Uint8Array(parts.reduce((size, part) => size + part.length, 0));
100
+ let offset = 0;
101
+ for (const part of parts) {
102
+ out.set(part, offset);
103
+ offset += part.length;
104
+ }
105
+ return out;
106
+ }
107
+ function fields(bytes) {
108
+ const out = new Map();
109
+ let offset = 0;
110
+ while (offset < bytes.length) {
111
+ const tag = readVarint(bytes, offset);
112
+ offset = tag.next;
113
+ const field = Math.floor(tag.value / 8);
114
+ const wire = tag.value % 8;
115
+ if (field <= 0)
116
+ fail("Scenario protobuf field 无效");
117
+ if (wire === 0) {
118
+ offset = readVarint(bytes, offset).next;
119
+ continue;
120
+ }
121
+ if (wire !== 2)
122
+ fail("Scenario protobuf 包含不支持字段");
123
+ const length = readVarint(bytes, offset);
124
+ offset = length.next;
125
+ const end = offset + length.value;
126
+ if (end > bytes.length)
127
+ fail("Scenario protobuf length 被截断");
128
+ const values = out.get(field) ?? [];
129
+ values.push(bytes.slice(offset, end));
130
+ out.set(field, values);
131
+ offset = end;
132
+ }
133
+ return out;
134
+ }
135
+ function first(map, field) { return map.get(field)?.[0] ?? new Uint8Array(); }
136
+ function protobufSegments(bytes) {
137
+ const result = [];
138
+ let offset = 0;
139
+ while (offset < bytes.length) {
140
+ const start = offset;
141
+ const tag = readVarint(bytes, offset);
142
+ offset = tag.next;
143
+ const field = Math.floor(tag.value / 8);
144
+ const wire = tag.value % 8;
145
+ if (field <= 0 || (wire !== 0 && wire !== 2))
146
+ fail("Scenario protobuf 包含不支持字段");
147
+ if (wire === 0) {
148
+ const value = readVarint(bytes, offset);
149
+ offset = value.next;
150
+ result.push({ field, wire, encoded: bytes.slice(start, offset), varintValue: value.value });
151
+ continue;
152
+ }
153
+ const length = readVarint(bytes, offset);
154
+ offset = length.next;
155
+ const end = offset + length.value;
156
+ if (end > bytes.length)
157
+ fail("Scenario protobuf length 被截断");
158
+ result.push({ field, wire, encoded: bytes.slice(start, end), payload: bytes.slice(offset, end) });
159
+ offset = end;
160
+ }
161
+ return result;
162
+ }
163
+ function encodedField(field, value) { return concat([varint(field * 8 + 2), varint(value.length), value]); }
164
+ function replaceBytesField(message, fieldNumber, payload) {
165
+ const replacement = encodedField(fieldNumber, payload);
166
+ let replaced = false;
167
+ const output = [];
168
+ for (const segment of protobufSegments(message)) {
169
+ if (segment.field !== fieldNumber)
170
+ output.push(segment.encoded);
171
+ else if (!replaced) {
172
+ output.push(replacement);
173
+ replaced = true;
174
+ }
175
+ }
176
+ if (!replaced)
177
+ output.push(replacement);
178
+ return concat(output);
179
+ }
180
+ export function decodeSpatialWorldProtobuf(bytes) {
181
+ if (bytes === undefined)
182
+ return undefined;
183
+ const top = fields(bytes);
184
+ const topologyFields = fields(first(top, 3));
185
+ const topologySettings = first(topologyFields, 2);
186
+ const topology = topologySettings.length === 0 ? { kind: "freeform", width: 100, height: 100 } : record(JSON.parse(textDecoder.decode(topologySettings)), "spatial topology settings");
187
+ const kind = topology.kind === "grid" ? "grid" : "freeform";
188
+ const width = finiteCoordinate(topology.width, "spatial topology.width");
189
+ const height = finiteCoordinate(topology.height, "spatial topology.height");
190
+ if (width <= 0 || height <= 0)
191
+ fail("spatial topology 边界必须为正数");
192
+ const cellSize = topology.cellSize === undefined ? undefined : finiteCoordinate(topology.cellSize, "spatial topology.cellSize");
193
+ let generation;
194
+ try {
195
+ generation = topology.generation === undefined ? undefined : validatePlaneGeneration(topology.generation);
196
+ }
197
+ catch (error) {
198
+ return fail(error instanceof Error ? error.message : "PlaneGenerationV1 无效");
199
+ }
200
+ if (generation !== undefined && (generation.widthMeters !== width || generation.heightMeters !== height))
201
+ fail("spatial topology.generation 范围必须与 topology 一致");
202
+ let roadGeneration;
203
+ try {
204
+ roadGeneration = topology.roadGeneration === undefined ? undefined : validateRoadGeneration(topology.roadGeneration);
205
+ }
206
+ catch (error) {
207
+ return fail(error instanceof Error ? error.message : "RoadGenerationV1 无效");
208
+ }
209
+ let templateLibrary;
210
+ try {
211
+ templateLibrary = topology.templateLibrary === undefined ? undefined : validateSpatialTemplateLibrary(topology.templateLibrary);
212
+ }
213
+ catch (error) {
214
+ return fail(error instanceof Error ? error.message : "SpatialTemplateLibraryV1 无效");
215
+ }
216
+ let templates;
217
+ try {
218
+ templates = topology.templates === undefined ? undefined : validateSpatialTemplateConfiguration(topology.templates);
219
+ }
220
+ catch (error) {
221
+ return fail(error instanceof Error ? error.message : "SpatialTemplateConfigurationV1 无效");
222
+ }
223
+ let procedural;
224
+ try {
225
+ procedural = topology.procedural === undefined ? undefined : validateProceduralWorld(topology.procedural, { widthMeters: width, heightMeters: height });
226
+ }
227
+ catch (error) {
228
+ return fail(error instanceof Error ? error.message : "ProceduralWorldV1 无效");
229
+ }
230
+ if (procedural !== undefined && generation === undefined)
231
+ fail("spatial topology.procedural 必须绑定 generation");
232
+ if (procedural !== undefined && generation !== undefined && procedural.worldSeed !== generation.seed)
233
+ fail("procedural.worldSeed 必须与 generation.seed 一致");
234
+ const actorId = controlledActorId(topology.controlledActorId, "spatial topology.controlledActorId");
235
+ const objects = [];
236
+ for (const field of [7, 8, 9, 10, 11])
237
+ for (const value of top.get(field) ?? []) {
238
+ const object = fields(value);
239
+ const id = stringValue(textDecoder.decode(first(object, 1)), "spatial object id");
240
+ const label = stringValue(textDecoder.decode(first(object, 3)), "spatial object label");
241
+ const settingsBytes = first(object, 4);
242
+ const settings = settingsBytes.length === 0 ? {} : record(JSON.parse(textDecoder.decode(settingsBytes)), "spatial author settings");
243
+ const inferred = field === 7 ? "location" : field === 8 ? "portal" : "region";
244
+ const objectKind = settings.kind === undefined ? inferred : spatialKind(settings.kind, "spatial object kind");
245
+ const key = typeof settings.key === "string" ? settings.key : id.split(":").at(-1) ?? "";
246
+ if (!SPATIAL_KEY.test(key))
247
+ fail("spatial object key 无效");
248
+ const x = settings.x === undefined ? 0 : finiteCoordinate(settings.x, "spatial object x");
249
+ const y = settings.y === undefined ? 0 : finiteCoordinate(settings.y, "spatial object y");
250
+ if (x < 0 || x > width || y < 0 || y > height)
251
+ fail("spatial object 坐标超出 topology");
252
+ const references = Array.isArray(settings.references) ? settings.references.map((entry) => {
253
+ const ref = record(entry, "spatial reference");
254
+ const candidate = ref.ownerKind;
255
+ if (candidate !== "ladybug" && candidate !== "trigger" && candidate !== "scenario")
256
+ fail("spatial reference ownerKind 无效");
257
+ return { ownerId: stringValue(ref.ownerId, "spatial reference ownerId"), ownerKind: candidate, fieldPath: stringValue(ref.fieldPath, "spatial reference fieldPath") };
258
+ }) : [];
259
+ const decoded = { id, key, kind: objectKind, label, x, y, references, _wireField: field, _wireBase64: bytesToBase64(value), _authorSettings: settings };
260
+ decoded._wireSignature = spatialObjectSignature(decoded);
261
+ objects.push(decoded);
262
+ }
263
+ const topologyBytes = first(top, 3);
264
+ const topologyWireKind = protobufSegments(topologyBytes).find((segment) => segment.field === 1 && segment.wire === 0)?.varintValue;
265
+ const { worldId: storedWorldId, spatialRevision: storedSpatialRevision, ...topologySettingsWithoutWorldId } = topology;
266
+ void storedWorldId;
267
+ const spatialRevision = storedSpatialRevision ?? 0;
268
+ if (!Number.isSafeInteger(spatialRevision) || spatialRevision < 0)
269
+ fail("spatialRevision 必须是非负安全整数");
270
+ const normalizedTopology = { ...topologySettingsWithoutWorldId, kind, width, height, ...(cellSize === undefined ? {} : { cellSize }), ...(generation === undefined ? {} : { generation }), ...(roadGeneration === undefined ? {} : { roadGeneration }), ...(templateLibrary === undefined ? {} : { templateLibrary }), ...(templates === undefined ? {} : { templates }), ...(procedural === undefined ? {} : { procedural }), ...(actorId === undefined ? {} : { controlledActorId: actorId }) };
271
+ return { schemaVersion: 1, worldId: typeof topology.worldId === "string" && SPATIAL_KEY.test(topology.worldId) ? topology.worldId : "world", spatialRevision: spatialRevision, topology: normalizedTopology, objects,
272
+ _wireBase64: bytesToBase64(bytes), _topologyWireBase64: bytesToBase64(topologyBytes), ...(topologyWireKind === undefined ? {} : { _topologyWireKind: topologyWireKind }) };
273
+ }
274
+ export function encodeSpatialWorldProtobuf(world) {
275
+ if (world === undefined)
276
+ return undefined;
277
+ const topologySettings = stableJson({ ...world.topology, worldId: world.worldId, spatialRevision: world.spatialRevision });
278
+ const topologyPayload = world._topologyWireBase64 === undefined
279
+ ? concat([varint(8), varint(2), encodedField(2, topologySettings)])
280
+ : replaceBytesField(base64ToBytes(world._topologyWireBase64), 2, topologySettings);
281
+ const encodeObject = (object) => {
282
+ const settings = stableJson({ ...(object._authorSettings ?? {}), key: object.key, kind: object.kind, x: object.x, y: object.y, references: object.references });
283
+ const raw = object._wireBase64 === undefined ? new Uint8Array() : base64ToBytes(object._wireBase64);
284
+ const payload = raw.length === 0
285
+ ? concat([encodedField(1, textEncoder.encode(object.id)), encodedField(3, textEncoder.encode(object.label)), encodedField(4, settings)])
286
+ : replaceBytesField(replaceBytesField(replaceBytesField(raw, 1, textEncoder.encode(object.id)), 3, textEncoder.encode(object.label)), 4, settings);
287
+ return encodedField(object._wireField ?? 7, payload);
288
+ };
289
+ if (world._wireBase64 === undefined)
290
+ return concat([varint(8), varint(1), encodedField(3, topologyPayload), ...world.objects.map(encodeObject)]);
291
+ const remaining = new Set(world.objects);
292
+ const output = [];
293
+ let topologyWritten = false;
294
+ for (const segment of protobufSegments(base64ToBytes(world._wireBase64))) {
295
+ if (segment.field === 3) {
296
+ if (!topologyWritten) {
297
+ output.push(encodedField(3, topologyPayload));
298
+ topologyWritten = true;
299
+ }
300
+ continue;
301
+ }
302
+ if (segment.field >= 7 && segment.field <= 11 && segment.payload !== undefined) {
303
+ const rawBase64 = bytesToBase64(segment.payload);
304
+ const object = world.objects.find((candidate) => candidate._wireBase64 === rawBase64);
305
+ if (object !== undefined) {
306
+ output.push(object._wireSignature === spatialObjectSignature(object) ? segment.encoded : encodeObject(object));
307
+ remaining.delete(object);
308
+ }
309
+ continue;
310
+ }
311
+ output.push(segment.encoded);
312
+ }
313
+ if (!topologyWritten)
314
+ output.push(encodedField(3, topologyPayload));
315
+ output.push(...[...remaining].map(encodeObject));
316
+ return concat(output);
317
+ }
@@ -0,0 +1,52 @@
1
+ export declare const ROAD_GENERATION_PROFILE: "terrain-roads-v1";
2
+ /**
3
+ * 绑定路径搜索、桥隧门户、地形采样和地块图语义的 canonical 规则字节。
4
+ * 任一语义变更都必须更新这份 JSON 并发布新 identity。
5
+ */
6
+ export declare const LEGACY_V6_ROAD_GENERATION_RULES_CANONICAL: "{\"algorithm\":\"direction-state-a-star-v2;32-coprime-neighbors;stable-heap-tie-order;route-edge-cache-v1\",\"anchor\":\"city-guide-anchor-once;whole-candidate-single-connectors;no-grid-exact-grid-pair-foldback-v3\",\"bridge\":\"complete-dry-portal-water-span-v1;linear-deck-3d-length-at-most-maxBridgeLengthMeters;all-water-interior;no-shortcut-or-split-v2\",\"cityAccess\":\"surface-street-node-short-connect-v1;radius-over-block-times-1.5-ceil-4to12;candidate-distance-0.75to3-block;target-1.7-block;stable-city-seed-node-pair-sort;surface-only-existing-nodes;actual-sampler-direct-or-bounded-astar;complete-portal-no-acute-boundary-containment;access-unreachable-domain-v1\",\"cityBoundary\":\"radial-budget-v2;world-seed-city-seed-city-id-fnv1a-xor;24to128-rays;step-at-most10m;phase-smooth-three-harmonics-radius-0.85to1.15;actual-sampler-surface-or-complete-classify-edge-portal;surface-abs-grade-integral-ds-times-1-plus-0.6-normalized-grade-over-one-minus-normalized;normalized-grade-at-least-0.995-reject;bounded-ccw-nonclosed-3to128|unbuildable-empty;city-road-continuous-points-inside-boundary;intercity-unclipped\",\"cityField\":\"seeded-radial-terrain-contour-guide-v1\",\"direction\":\"heading-dot-at-least-zero;interior-angle-at-least90deg;all-assembled-route-final-gate-v2\",\"elevation\":\"relative-height-times-elevationScaleMeters-v1\",\"limits\":\"maxGrade-roadWidthMeters-maxBridgeLengthMeters-maxTunnelLengthMeters-v1\",\"parcelFace\":\"road-parcels-v4-boundary-highway;cityId-exact-arterial-local-street-surface-only;quantized-strict-xy-intersection-split;dcel-left-turn;positive-inside-concave-boundary;oriented-length-weighted-second-moment-principal-axis;canonical-longest-edge-isotropic-fallback;projection-midline-clip;area22500-recursion-depth8;inset-half-widest-road-plus-setback;triangulated-max-square-safe-bounds-v4\",\"parcelFrontage\":\"face-plus-uncovered-frontage-v1;cityId-exact-arterial-local-street-surface-elementary-run;polyline-slice-16to42m;two-sided-offset;depth-clamp-blockSize-times-0.18-10to20;source-and-road-corridor-clear;face-first-frontage-positive-area-nonoverlap-stable-id-greedy-v1\",\"parcelGraph\":\"road-parcels-v4-boundary-highway\",\"parcelIdentity\":\"boundary-token-sorted-hash-worldSeed-citySeed-cityId;oriented-split-normal-token;frontage-side-and-ordinal;weighted-land-use;id-sort-v3\",\"parcelTerrain\":\"polygon-touching-cells-dry-finite;adjacent-touching-cell-slope-at-most-settings-maxSlope;grid-at-most257-v1\",\"portalLookahead\":\"complete-portal-before-partial-surface-v1;exact-dry-grid-portal-preserved-v1;off-grid-origin-requires-validated-surface-connector-v1;connector-budget-cost-required-v1\",\"repair\":\"same-core-segment-splice;10m-grid;at-most8-attempts;min-margin200m-v1\",\"roadClass\":\"required-kind-intercity-arterial-local;required-class-street-motorway;intercity-motorway-else-street;all-intercity-motorway-and-city-nonbuildable-roads-forbidden-corridor;centerline-no-intersection-or-containment;clearance-half-width-plus-setback-v1\",\"shortcut\":\"surface-run-control-edge-boundaries;candidates-i-to-j-j-at-most-i-plus24-or-last;actual-sampler-water-grade-step-at-most10m;reverse-sparse-dag-heading-compatible-dot-epsilon1e-12;no-accumulated-cost;farthest-reachable-stable-descending;retain-original-if-no-complete-chain;whole-road-stable-branch-unreachable-if-final-acute;bridge-tunnel-excluded-v3\",\"terrain\":\"canonical-plane-hydrology-fixed-sampling;global-long-axis257;city-long-axis65to257;actual-finite-sampler-step10m;no-sub10m-obstacle-guarantee-v1\",\"tunnel\":\"covered-dry-portal-bore;actual-cover-at-least1m;3d-length-at-most-maxTunnelLengthMeters;no-shortcut-or-split;no-water-interior;roadWidth-surface-abutment-v2\",\"version\":6}";
7
+ /**
8
+ * 该字符串绑定 profile、算法版本与上方 canonical 规则字节的 SHA-256。
9
+ * 道路语义变化时必须发布新 identity,禁止让旧世界静默重算为不同结果。
10
+ */
11
+ export declare const LEGACY_V6_IDENTITY: "chat.worldengine.terrain-roads/v1;rules-sha256=9dc32e6e3f5e63fbf378d6b83dfa67c2e9d62dabfebe5b432956f7ff0fdb8443";
12
+ export declare const STRUCTURED_V8_ROAD_GENERATION_RULES_CANONICAL: "{\"version\":8,\"algorithm\":\"direction-state-a-star-v2;32-coprime-neighbors;stable-heap-tie-order;route-edge-cache-v1\",\"cityField\":\"structured-two-family-seeded-skeleton-v8;candidate-only-actual-terrain-router-required\",\"cityCandidateBudget\":\"boundary-polygon-shoelace-abs-area-m2;ceil-sqrt-area-over-block-times-0.42-per-family;clamp6to15;not-nominal-radius-area;not-feasible-terrain-mask\",\"cityCandidateFamilies\":\"six-arterial-rays-from-center-four-collinear-points;arterial-base-seeded-angle-plus-sixth-turn-plus-seeded-jitter;two-transverse-families-base-and-base-plus-pi-over-two-plus-seeded-0.18rad;collector-and-local;four-point-parabolic-sweeps;seeded-bend-block-times-0.32;actual-terrain-and-boundary-gates\",\"cityBoundary\":\"radial-budget-v2;world-seed-city-seed-city-id-fnv1a-xor;24to128-rays;step-at-most10m;phase-smooth-three-harmonics-radius-0.85to1.15;actual-sampler-surface-or-complete-classify-edge-portal;surface-abs-grade-integral-ds-times-1-plus-0.6-normalized-grade-over-one-minus-normalized;normalized-grade-at-least-0.995-reject;bounded-ccw-nonclosed-3to128|unbuildable-empty;city-road-continuous-points-inside-boundary;intercity-unclipped\",\"cityStructuredClip\":\"v8-nonarterial-all-exact-boundary-inside-runs;candidate-segment-boundary-intersections;boundary-inclusive;rooted-run-nearest-original-sweep-midpoint-else-inside-run-nearest-midpoint;arterial-uses-legacy-origin-first-exit-clip;final-route-sample-boundary-verify-at-most10m\",\"cityStructuredRoot\":\"v8-transverse-same-city-surface-strict-internal-xy-intersection;parallel-collinear-endpoint-near-end-reject-epsilon1e-9;nearest-original-sweep-midpoint-then-stable-road-segment-point-pair-tie-order;root-z-actual-terrain-sample;both-old-surface-halves-revalidate-before-noding\",\"cityRootArms\":\"root-left-right-independent-anchor-direct-or-bounded-astar-finish-and-boundary-check;both-concatenate|one-commit-valid-arm-and-record-other-unreachable|none-reject;assembled-root-route-no-acute-final-gate;preserve-root-xy\",\"citySurfaceNoding\":\"v8-same-city-nonintercity-surface-only;strict-internal-xy-crossing-with-nonfinite-reject-and-dimensionless-interior-epsilon1e-9|positive-collinear-xy-overlap-line-distance-at-most1e-7;canonical-overlap-endpoints-xy-round-1e-7m-and-z-actual-terrain-sample;all-four-half-edges-or-local-endpoint-replacement-surface-revalidate;stable-road-segment-original-edge-index-descending-and-t-descending-insert-order;not-cross-city-bridge-tunnel-or-general-grade-separation\",\"cityExactSurfaceReuse\":\"after-same-city-surface-noding-and-common-overlap-endpoint-rewrite;same-city-nonintercity-contiguous-all-surface-normalized-run-only-without-crossing-bridge-or-tunnel;undirected-exact-xyz-bit-elementary-key;arterial-then-local-then-lexical-road-id-owner;partial-overlap-reuse-removes-nonowner-exact-pieces-retains-continuous-chains;single-retained-chain-keeps-parent-id|multiple-retained-chains-child-id-parent-plus-retained-child-first-last-xy-IEEE-bits-and-reuse-purpose-no-ordinal;refresh-sorted-layout-ids;no-reuse-status-output;not-near-or-unvalidated-overlap-reuse\",\"cityAccess\":\"legacy-v6-only:surface-street-node-short-connect-v1;radius-over-block-times-1.5-ceil-4to12;candidate-distance-0.75to3-block;target-1.7-block;stable-city-seed-node-pair-sort;surface-only-existing-nodes;actual-sampler-direct-or-bounded-astar;complete-portal-no-acute-boundary-containment;access-unreachable-domain-v1\",\"parcelFace\":\"structured-v8-convex-closed-face-with-every-simplified-edge-matched-to-real-ordinary-street-elementary-frontage-only;per-edge-inward-half-plane-offset-before-split;clearance-max-matching-edge-half-width-plus-nonnegative-setback;mixed-width-collinear-match-uses-max-conservative-clearance;nonconvex-unmatched-or-invalid-offset-closed-face-reject-no-topology-guess\",\"parcelSplit\":\"structured-v8-projection-midline-clip-area-settings-maxFaceAreaMeters-default22500-recursion-depth8;each-child-needs-longest-continuous-collinear-overlap-with-inset-real-street-frontage-at-least-max-10-min-20-widest-road;not-fragment-sum;on-failure-retain-parent-unsplit;cut-edge-is-not-frontage\",\"parcelFrontage\":\"face-plus-uncovered-frontage-v1;open-area-only-real-surface-ordinary-street-segment-run;polyline-slice-min16-max42-except-unsplittable-first-edge-may-exceed42;two-sided-offset;inner-road-corridor-clearance-plus-0.01;source-run-clearance-recheck-at-least-clearance-minus0.2;depth-clamp-blockSize-times-0.18-10to20;source-and-road-corridor-clear;face-first-frontage-positive-area-nonoverlap-stable-id-greedy-v1;no-entrance-or-navigation-reachability-claim\",\"legacyParcel\":\"legacy-v6-undefined-or-explicit-legacy-uses-prior-split-and-centroid-inset-path;v8-only-convex-offset-and-child-frontage-rule;shared-invalid-algorithm-fail-closed\",\"parcelGraph\":\"road-parcels-v4-boundary-highway\",\"parcelIdentity\":\"boundary-token-sorted-hash-worldSeed-citySeed-cityId;oriented-split-normal-token;frontage-side-and-ordinal;weighted-land-use;id-sort-v3\",\"parcelTerrain\":\"polygon-touching-cells-dry-finite;adjacent-touching-cell-slope-at-most-settings-maxSlope;grid-at-most257-v1\",\"roadClass\":\"required-kind-intercity-arterial-local;required-class-street-motorway;intercity-motorway-else-street;all-intercity-motorway-and-city-nonbuildable-roads-forbidden-corridor;centerline-no-intersection-or-containment;clearance-half-width-plus-setback-v1\",\"direction\":\"heading-dot-at-least-zero;interior-angle-at-least90deg;all-assembled-route-final-gate-v2\",\"limits\":\"maxGrade-roadWidthMeters-maxBridgeLengthMeters-maxTunnelLengthMeters-v1\",\"elevation\":\"relative-height-times-elevationScaleMeters-v1\",\"terrain\":\"canonical-plane-hydrology-fixed-sampling;global-long-axis257;city-long-axis65to257;actual-finite-sampler-step10m;no-sub10m-obstacle-guarantee-v1\",\"portalLookahead\":\"complete-portal-before-partial-surface-v1;exact-dry-grid-portal-preserved-v1;off-grid-origin-requires-validated-surface-connector-v1;connector-budget-cost-required-v1\",\"bridge\":\"complete-dry-portal-water-span-v1;linear-deck-3d-length-at-most-maxBridgeLengthMeters;all-water-interior;no-shortcut-or-split-v2\",\"tunnel\":\"covered-dry-portal-bore;actual-cover-at-least1m;3d-length-at-most-maxTunnelLengthMeters;no-shortcut-or-split;no-water-interior;roadWidth-surface-abutment-v2\",\"shortcut\":\"surface-run-control-edge-boundaries;candidates-i-to-j-j-at-most-i-plus24-or-last;actual-sampler-water-grade-step-at-most10m;reverse-sparse-dag-heading-compatible-dot-epsilon1e-12;no-accumulated-cost;farthest-reachable-stable-descending;retain-original-if-no-complete-chain;whole-road-stable-branch-unreachable-if-final-acute;bridge-tunnel-excluded-v3\",\"repair\":\"same-core-segment-splice;10m-grid;at-most8-attempts;min-margin200m-v1\"}";
13
+ export declare const STRUCTURED_V8_IDENTITY: "chat.worldengine.terrain-roads/v1;rules-sha256=03ab0544e8fdfc741045dccac18a946eb95b76bc10e9880012cba50060b29b4f";
14
+ export declare const FRONTAGE_BALANCED_V9_ROAD_GENERATION_RULES_CANONICAL: "{\"version\":9,\"algorithm\":\"direction-state-a-star-v2;32-coprime-neighbors;stable-heap-tie-order;route-edge-cache-v1\",\"cityField\":\"structured-two-family-seeded-skeleton-v8;candidate-only-actual-terrain-router-required\",\"cityCandidateBudget\":\"boundary-polygon-shoelace-abs-area-m2;ceil-sqrt-area-over-block-times-0.42-per-family;clamp6to15;not-nominal-radius-area;not-feasible-terrain-mask\",\"cityCandidateFamilies\":\"six-arterial-rays-from-center-four-collinear-points;arterial-base-seeded-angle-plus-sixth-turn-plus-seeded-jitter;two-transverse-families-base-and-base-plus-pi-over-two-plus-seeded-0.18rad;collector-and-local;four-point-parabolic-sweeps;seeded-bend-block-times-0.32;actual-terrain-and-boundary-gates\",\"cityBoundary\":\"radial-budget-v2;world-seed-city-seed-city-id-fnv1a-xor;24to128-rays;step-at-most10m;phase-smooth-three-harmonics-radius-0.85to1.15;actual-sampler-surface-or-complete-classify-edge-portal;surface-abs-grade-integral-ds-times-1-plus-0.6-normalized-grade-over-one-minus-normalized;normalized-grade-at-least-0.995-reject;bounded-ccw-nonclosed-3to128|unbuildable-empty;city-road-continuous-points-inside-boundary;intercity-unclipped\",\"cityStructuredClip\":\"v8-nonarterial-all-exact-boundary-inside-runs;candidate-segment-boundary-intersections;boundary-inclusive;rooted-run-nearest-original-sweep-midpoint-else-inside-run-nearest-midpoint;arterial-uses-legacy-origin-first-exit-clip;final-route-sample-boundary-verify-at-most10m\",\"cityStructuredRoot\":\"v8-transverse-same-city-surface-strict-internal-xy-intersection;parallel-collinear-endpoint-near-end-reject-epsilon1e-9;nearest-original-sweep-midpoint-then-stable-road-segment-point-pair-tie-order;root-z-actual-terrain-sample;both-old-surface-halves-revalidate-before-noding\",\"cityRootArms\":\"root-left-right-independent-anchor-direct-or-bounded-astar-finish-and-boundary-check;both-concatenate|one-commit-valid-arm-and-record-other-unreachable|none-reject;assembled-root-route-no-acute-final-gate;preserve-root-xy\",\"citySurfaceNoding\":\"v8-same-city-nonintercity-surface-only;strict-internal-xy-crossing-with-nonfinite-reject-and-dimensionless-interior-epsilon1e-9|positive-collinear-xy-overlap-line-distance-at-most1e-7;canonical-overlap-endpoints-xy-round-1e-7m-and-z-actual-terrain-sample;all-four-half-edges-or-local-endpoint-replacement-surface-revalidate;stable-road-segment-original-edge-index-descending-and-t-descending-insert-order;not-cross-city-bridge-tunnel-or-general-grade-separation\",\"cityExactSurfaceReuse\":\"after-same-city-surface-noding-and-common-overlap-endpoint-rewrite;same-city-nonintercity-contiguous-all-surface-normalized-run-only-without-crossing-bridge-or-tunnel;undirected-exact-xyz-bit-elementary-key;arterial-then-local-then-lexical-road-id-owner;partial-overlap-reuse-removes-nonowner-exact-pieces-retains-continuous-chains;single-retained-chain-keeps-parent-id|multiple-retained-chains-child-id-parent-plus-retained-child-first-last-xy-IEEE-bits-and-reuse-purpose-no-ordinal;refresh-sorted-layout-ids;no-reuse-status-output;not-near-or-unvalidated-overlap-reuse\",\"cityAccess\":\"legacy-v6-only:surface-street-node-short-connect-v1;radius-over-block-times-1.5-ceil-4to12;candidate-distance-0.75to3-block;target-1.7-block;stable-city-seed-node-pair-sort;surface-only-existing-nodes;actual-sampler-direct-or-bounded-astar;complete-portal-no-acute-boundary-containment;access-unreachable-domain-v1\",\"parcelAlgorithm\":\"identity-bound-v1;v6=legacy-v6-road-core-and-parcels;v8=structured-v8-road-core-and-parcels;v9=structured-v8-road-core-plus-frontage-balanced-v9-parcels;v9-vs-v8-selects-parcel-only;no-load-time-upgrade\",\"parcelFace\":\"structured-v8-convex-closed-face-with-every-simplified-edge-matched-to-real-ordinary-street-elementary-frontage-only;per-edge-inward-half-plane-offset-before-split;clearance-max-matching-edge-half-width-plus-nonnegative-setback;mixed-width-collinear-match-uses-max-conservative-clearance;nonconvex-unmatched-or-invalid-offset-closed-face-reject-no-topology-guess\",\"parcelSplit\":\"frontage-balanced-v9-primary-structured-v8-projection-midline-clip-area-settings-maxFaceAreaMeters-default22500;each-child-needs-longest-continuous-collinear-overlap-with-inset-real-street-frontage-at-least-max-10-min-20-widest-road;not-fragment-sum;when-primary-area-frontage-invalid-try-real-inset-frontage-overlap-cuts-length-desc-edge-id-normal-key;canonical-positive-frontage-tangent-normal;cut-overlap-midpoint-projection;dedup-normal-and-cut;first-area-frontage-valid-candidate;recursive-split-depth8;emitted-children-pass-existing-final-terrain-corridor-nonoverlap-gates;no-retry-after-final-rejection;on-all-area-frontage-failure-retain-parent-unsplit;cut-edge-is-not-frontage\",\"parcelFrontage\":\"face-plus-uncovered-frontage-v1;open-area-only-real-surface-ordinary-street-segment-run;polyline-slice-min16-max42-except-unsplittable-first-edge-may-exceed42;two-sided-offset;inner-road-corridor-clearance-plus-0.01;source-run-clearance-recheck-at-least-clearance-minus0.2;depth-clamp-blockSize-times-0.18-10to20;source-and-road-corridor-clear;face-first-frontage-positive-area-nonoverlap-stable-id-greedy-v1;no-entrance-or-navigation-reachability-claim\",\"legacyParcel\":\"legacy-v6-undefined-or-explicit-legacy-uses-prior-split-and-centroid-inset-path;structured-v8-uses-convex-offset-and-primary-child-frontage-rule;frontage-balanced-v9-keeps-v8-road-core-face-inset-and-primary-split-plus-stable-frontage-cut-fallback;shared-invalid-algorithm-fail-closed\",\"parcelGraph\":\"road-parcels-v4-boundary-highway\",\"parcelIdentity\":\"boundary-token-sorted-hash-worldSeed-citySeed-cityId;oriented-split-normal-token;frontage-side-and-ordinal;weighted-land-use;id-sort-v3\",\"parcelTerrain\":\"polygon-touching-cells-dry-finite;adjacent-touching-cell-slope-at-most-settings-maxSlope;grid-at-most257-v1\",\"roadClass\":\"required-kind-intercity-arterial-local;required-class-street-motorway;intercity-motorway-else-street;all-intercity-motorway-and-city-nonbuildable-roads-forbidden-corridor;centerline-no-intersection-or-containment;clearance-half-width-plus-setback-v1\",\"direction\":\"heading-dot-at-least-zero;interior-angle-at-least90deg;all-assembled-route-final-gate-v2\",\"limits\":\"maxGrade-roadWidthMeters-maxBridgeLengthMeters-maxTunnelLengthMeters-v1\",\"elevation\":\"relative-height-times-elevationScaleMeters-v1\",\"terrain\":\"canonical-plane-hydrology-fixed-sampling;global-long-axis257;city-long-axis65to257;actual-finite-sampler-step10m;no-sub10m-obstacle-guarantee-v1\",\"portalLookahead\":\"complete-portal-before-partial-surface-v1;exact-dry-grid-portal-preserved-v1;off-grid-origin-requires-validated-surface-connector-v1;connector-budget-cost-required-v1\",\"bridge\":\"complete-dry-portal-water-span-v1;linear-deck-3d-length-at-most-maxBridgeLengthMeters;all-water-interior;no-shortcut-or-split-v2\",\"tunnel\":\"covered-dry-portal-bore;actual-cover-at-least1m;3d-length-at-most-maxTunnelLengthMeters;no-shortcut-or-split;no-water-interior;roadWidth-surface-abutment-v2\",\"shortcut\":\"surface-run-control-edge-boundaries;candidates-i-to-j-j-at-most-i-plus24-or-last;actual-sampler-water-grade-step-at-most10m;reverse-sparse-dag-heading-compatible-dot-epsilon1e-12;no-accumulated-cost;farthest-reachable-stable-descending;retain-original-if-no-complete-chain;whole-road-stable-branch-unreachable-if-final-acute;bridge-tunnel-excluded-v3\",\"repair\":\"same-core-segment-splice;10m-grid;at-most8-attempts;min-margin200m-v1\"}";
15
+ export declare const FRONTAGE_BALANCED_V9_IDENTITY: "chat.worldengine.terrain-roads/v1;rules-sha256=671b01df50d378c85208f910ba10e63ff5b03d3787619898c8de60453329b38b";
16
+ export declare const ROAD_GENERATION_RULES_CANONICAL: "{\"version\":10,\"algorithm\":\"direction-state-a-star-v2;32-coprime-neighbors;stable-heap-tie-order;route-edge-cache-v1\",\"cityField\":\"structured-two-family-seeded-skeleton-v8;candidate-only-actual-terrain-router-required\",\"cityCandidateBudget\":\"boundary-polygon-shoelace-abs-area-m2;ceil-sqrt-area-over-block-times-0.42-per-family;clamp6to15;not-nominal-radius-area;not-feasible-terrain-mask\",\"cityCandidateFamilies\":\"six-arterial-rays-from-center-four-collinear-points;arterial-base-seeded-angle-plus-sixth-turn-plus-seeded-jitter;two-transverse-families-base-and-base-plus-pi-over-two-plus-seeded-0.18rad;collector-and-local;four-point-parabolic-sweeps;seeded-bend-block-times-0.32;actual-terrain-and-boundary-gates\",\"cityBoundary\":\"radial-budget-v2;world-seed-city-seed-city-id-fnv1a-xor;24to128-rays;step-at-most10m;phase-smooth-three-harmonics-radius-0.85to1.15;actual-sampler-surface-or-complete-classify-edge-portal;surface-abs-grade-integral-ds-times-1-plus-0.6-normalized-grade-over-one-minus-normalized;normalized-grade-at-least-0.995-reject;bounded-ccw-nonclosed-3to128|unbuildable-empty;city-road-continuous-points-inside-boundary;intercity-unclipped\",\"cityStructuredClip\":\"v8-nonarterial-all-exact-boundary-inside-runs;candidate-segment-boundary-intersections;boundary-inclusive;rooted-run-nearest-original-sweep-midpoint-else-inside-run-nearest-midpoint;arterial-uses-legacy-origin-first-exit-clip;final-route-sample-boundary-verify-at-most10m\",\"cityStructuredRoot\":\"v8-transverse-same-city-surface-strict-internal-xy-intersection;parallel-collinear-endpoint-near-end-reject-epsilon1e-9;nearest-original-sweep-midpoint-then-stable-road-segment-point-pair-tie-order;root-z-actual-terrain-sample;both-old-surface-halves-revalidate-before-noding\",\"cityRootArms\":\"root-left-right-independent-anchor-direct-or-bounded-astar-finish-and-boundary-check;both-concatenate|one-commit-valid-arm-and-record-other-unreachable|none-reject;assembled-root-route-no-acute-final-gate;preserve-root-xy\",\"citySurfaceNoding\":\"v8-same-city-nonintercity-surface-only;strict-internal-xy-crossing-with-nonfinite-reject-and-dimensionless-interior-epsilon1e-9|positive-collinear-xy-overlap-line-distance-at-most1e-7;canonical-overlap-endpoints-xy-round-1e-7m-and-z-actual-terrain-sample;all-four-half-edges-or-local-endpoint-replacement-surface-revalidate;stable-road-segment-original-edge-index-descending-and-t-descending-insert-order;not-cross-city-bridge-tunnel-or-general-grade-separation\",\"cityExactSurfaceReuse\":\"after-same-city-surface-noding-and-common-overlap-endpoint-rewrite;same-city-nonintercity-contiguous-all-surface-normalized-run-only-without-crossing-bridge-or-tunnel;undirected-exact-xyz-bit-elementary-key;arterial-then-local-then-lexical-road-id-owner;partial-overlap-reuse-removes-nonowner-exact-pieces-retains-continuous-chains;single-retained-chain-keeps-parent-id|multiple-retained-chains-child-id-parent-plus-retained-child-first-last-xy-IEEE-bits-and-reuse-purpose-no-ordinal;refresh-sorted-layout-ids;no-reuse-status-output;not-near-or-unvalidated-overlap-reuse\",\"cityAccess\":\"legacy-v6-only:surface-street-node-short-connect-v1;radius-over-block-times-1.5-ceil-4to12;candidate-distance-0.75to3-block;target-1.7-block;stable-city-seed-node-pair-sort;surface-only-existing-nodes;actual-sampler-direct-or-bounded-astar;complete-portal-no-acute-boundary-containment;access-unreachable-domain-v1\",\"parcelAlgorithm\":\"identity-bound-v1;v6=legacy-v6-road-core-and-parcels;v8=structured-v8-road-core-and-parcels;v9=structured-v8-road-core-plus-frontage-balanced-v9-parcels;v10=structured-v8-road-core-plus-shape-filled-v10-parcels;v10-vs-v9-selects-parcel-only;no-load-time-upgrade\",\"parcelFace\":\"shape-filled-v10-simple-single-ring-closed-face;real-ordinary-street-elementary-frontage-only;collinear-ring-simplify;per-edge-inward-offset-max-matching-real-road-half-width-plus-nonnegative-setback-plus-4epsilon-quantization-guard;inset-must-stay-within-source-and-strict-road-clearance;self-cross-reject;concave-ear-clip-then-stable-convex-merge;internal-chords-have-no-offset-and-no-frontage;unsupported-complex-or-hole-face-reject-no-topology-guess\",\"parcelSplit\":\"shape-filled-v10-long-axis-oriented-bounds-primary-then-stable-face-axis;projection-midline-clip-targets-settings-maxFaceAreaMeters-default22500-not-terminal-hard-limit;shape-context-cut-children-inset-by-4epsilon-per-side-leaving-8epsilon-artificial-nonroad-gap-to-prevent-quantized-shared-edge-positive-overlap;no-distance-or-overlap-gate-relaxation;both-children-area-at-least-settings-minParcelAreaMeters-default36;each-child-needs-longest-continuous-real-inset-street-frontage-at-least-max-10-min-20-widest-road;shape-node-and-recursive-output-hard-gates;pair-atomic-no-single-child-commit;frontage-balanced-real-inset-frontage-cut-fallback;recursive-depth8;at-depth-or-no-valid-cut-shape-valid-parent-may-remain-even-over-max-area;at-depth-or-no-valid-cut-invalid-shape-reject;cut-edge-is-not-frontage\",\"parcelFrontage\":\"shape-filled-v10-face-first-then-uncovered-frontage-only;closed-valid-inset-faces-fill-before-open-street;real-surface-ordinary-street-run-resampled-at-at-most-min-10-maxSliceLength;two-sided-offset;depth-at-least-blockSize-times-0.18-and-at-least-minShortSide-times-sqrt2-plus1;maxSliceLength-max-requiredStripDimension-plus10-only-when-requiredStripDimension-over42-and-min-42-maxAspectRatio-times-depth-so-minShortSide-override-remains-sliceable;slice-at-least-minShortSide-times-sqrt2-plus1;shape-safe-bounds-and-ratio-hard-gates;source-and-all-road-corridor-boundary-terrain-clear;positive-area-nonoverlap-stable-id-greedy;no-entrance-or-navigation-reachability-claim\",\"legacyParcel\":\"legacy-v6-undefined-or-explicit-legacy-uses-prior-split-and-centroid-inset-path;structured-v8-uses-convex-offset-and-primary-child-frontage-rule;frontage-balanced-v9-keeps-v8-road-core-face-inset-and-primary-split-plus-stable-frontage-cut-fallback;shape-filled-v10-keeps-v8-road-core-and-uses-simple-ring-inset-concave-decomposition-shape-hard-gates-and-uncovered-frontage-only;shared-invalid-algorithm-fail-closed\",\"parcelGraph\":\"road-parcels-v4-boundary-highway\",\"parcelIdentity\":\"boundary-token-sorted-hash-worldSeed-citySeed-cityId;oriented-split-normal-token;frontage-side-and-ordinal;weighted-land-use;id-sort-v3;shape-filled-v10-canonical-ring-ear-clip-first-valid-vertex-order-then-first-pair-convex-merge-loop;decomposed-piece-traversal-order-is-explicit-root-c-pieceIndex-and-affects-stable-id\",\"parcelTerrain\":\"polygon-touching-cells-dry-finite;adjacent-touching-cell-slope-at-most-settings-maxSlope;grid-at-most257-v1\",\"roadClass\":\"required-kind-intercity-arterial-local;required-class-street-motorway;intercity-motorway-else-street;all-intercity-motorway-and-city-nonbuildable-roads-forbidden-corridor;centerline-no-intersection-or-containment;clearance-half-width-plus-setback-v1\",\"direction\":\"heading-dot-at-least-zero;interior-angle-at-least90deg;all-assembled-route-final-gate-v2\",\"limits\":\"maxGrade-roadWidthMeters-maxBridgeLengthMeters-maxTunnelLengthMeters-v1\",\"elevation\":\"relative-height-times-elevationScaleMeters-v1\",\"terrain\":\"canonical-plane-hydrology-fixed-sampling;global-long-axis257;city-long-axis65to257;actual-finite-sampler-step10m;no-sub10m-obstacle-guarantee-v1\",\"portalLookahead\":\"complete-portal-before-partial-surface-v1;exact-dry-grid-portal-preserved-v1;off-grid-origin-requires-validated-surface-connector-v1;connector-budget-cost-required-v1\",\"bridge\":\"complete-dry-portal-water-span-v1;linear-deck-3d-length-at-most-maxBridgeLengthMeters;all-water-interior;no-shortcut-or-split-v2\",\"tunnel\":\"covered-dry-portal-bore;actual-cover-at-least1m;3d-length-at-most-maxTunnelLengthMeters;no-shortcut-or-split;no-water-interior;roadWidth-surface-abutment-v2\",\"shortcut\":\"surface-run-control-edge-boundaries;candidates-i-to-j-j-at-most-i-plus24-or-last;actual-sampler-water-grade-step-at-most10m;reverse-sparse-dag-heading-compatible-dot-epsilon1e-12;no-accumulated-cost;farthest-reachable-stable-descending;retain-original-if-no-complete-chain;whole-road-stable-branch-unreachable-if-final-acute;bridge-tunnel-excluded-v3\",\"repair\":\"same-core-segment-splice;10m-grid;at-most8-attempts;min-margin200m-v1\",\"parcelShape\":\"coordinates-round-decimal6-epsilon1e-6;minimum-oriented-convex-hull-edge-aligned-bounds;settings-maxAspectRatio-finite-at-least1-default4;settings-minShortSideMeters-finite-at-least26-default26;short-side-at-least-minShortSideMeters;long-side-at-most-short-side-times-maxAspectRatio;safe-axis-aligned-square-inside-polygon-width-and-height-at-least-minShortSideMeters;all-partition-nodes-and-emitted-parcels-terrain-boundary-corridor-clear\"}";
17
+ export declare const ROAD_GENERATION_IDENTITY: "chat.worldengine.terrain-roads/v1;rules-sha256=58fc51cfe9986a8da0cc6931c8600cf4c1afbbcda80f58e00038b76f982aec5b";
18
+ /**
19
+ * 已发布 identity 的精确 allowlist。新算法必须先有冻结的 rules digest,才能加入这里;
20
+ * 不得以“当前默认值”替换已保存 source 的 identity。
21
+ */
22
+ export declare const SUPPORTED_ROAD_GENERATION_IDENTITIES: readonly ["chat.worldengine.terrain-roads/v1;rules-sha256=9dc32e6e3f5e63fbf378d6b83dfa67c2e9d62dabfebe5b432956f7ff0fdb8443", "chat.worldengine.terrain-roads/v1;rules-sha256=03ab0544e8fdfc741045dccac18a946eb95b76bc10e9880012cba50060b29b4f", "chat.worldengine.terrain-roads/v1;rules-sha256=671b01df50d378c85208f910ba10e63ff5b03d3787619898c8de60453329b38b", "chat.worldengine.terrain-roads/v1;rules-sha256=58fc51cfe9986a8da0cc6931c8600cf4c1afbbcda80f58e00038b76f982aec5b"];
23
+ export type RoadGenerationIdentity = (typeof SUPPORTED_ROAD_GENERATION_IDENTITIES)[number];
24
+ /**
25
+ * 已保存 identity 到 core selector 的语义映射。source 只能按它自身的已发布 identity
26
+ * 重放;新默认值不得覆盖旧 source。
27
+ */
28
+ export type RoadGenerationAlgorithm = "legacy-v6" | "structured-v8";
29
+ export declare function roadGenerationAlgorithm(identity: RoadGenerationIdentity): RoadGenerationAlgorithm;
30
+ export type RoadParcelAlgorithm = "legacy-v6" | "structured-v8" | "frontage-balanced-v9" | "shape-filled-v10";
31
+ /** 已保存 identity 独立选择 parcel 语义;V9 仍复用已发布 V8 道路 core。 */
32
+ export declare function roadParcelAlgorithm(identity: RoadGenerationIdentity): RoadParcelAlgorithm;
33
+ /**
34
+ * 只有已冻结的后继 identity 才能令旧 source 出现显式升级预览入口。
35
+ * 加载或保存绝不能据此静默升级。
36
+ */
37
+ export declare function roadGenerationUpgradeTarget(identity: RoadGenerationIdentity): RoadGenerationIdentity | undefined;
38
+ export interface RoadGenerationV1 {
39
+ readonly profile: typeof ROAD_GENERATION_PROFILE;
40
+ readonly identity: RoadGenerationIdentity;
41
+ readonly allowBridges: boolean;
42
+ readonly allowTunnels: boolean;
43
+ readonly maxBridgeLengthMeters: number;
44
+ readonly maxTunnelLengthMeters: number;
45
+ readonly maxGrade: number;
46
+ readonly roadWidthMeters: number;
47
+ /** 相对地形高度值换算为米的比例。 */
48
+ readonly elevationScaleMeters: number;
49
+ }
50
+ export declare const DEFAULT_ROAD_GENERATION: Readonly<RoadGenerationV1>;
51
+ /** 严格验证桥隧道路设置,拒绝未知字段并返回不可变 canonical 副本。 */
52
+ export declare function validateRoadGeneration(input: unknown): RoadGenerationV1;
@@ -0,0 +1,129 @@
1
+ export const ROAD_GENERATION_PROFILE = "terrain-roads-v1";
2
+ /**
3
+ * 绑定路径搜索、桥隧门户、地形采样和地块图语义的 canonical 规则字节。
4
+ * 任一语义变更都必须更新这份 JSON 并发布新 identity。
5
+ */
6
+ export const LEGACY_V6_ROAD_GENERATION_RULES_CANONICAL = '{"algorithm":"direction-state-a-star-v2;32-coprime-neighbors;stable-heap-tie-order;route-edge-cache-v1","anchor":"city-guide-anchor-once;whole-candidate-single-connectors;no-grid-exact-grid-pair-foldback-v3","bridge":"complete-dry-portal-water-span-v1;linear-deck-3d-length-at-most-maxBridgeLengthMeters;all-water-interior;no-shortcut-or-split-v2","cityAccess":"surface-street-node-short-connect-v1;radius-over-block-times-1.5-ceil-4to12;candidate-distance-0.75to3-block;target-1.7-block;stable-city-seed-node-pair-sort;surface-only-existing-nodes;actual-sampler-direct-or-bounded-astar;complete-portal-no-acute-boundary-containment;access-unreachable-domain-v1","cityBoundary":"radial-budget-v2;world-seed-city-seed-city-id-fnv1a-xor;24to128-rays;step-at-most10m;phase-smooth-three-harmonics-radius-0.85to1.15;actual-sampler-surface-or-complete-classify-edge-portal;surface-abs-grade-integral-ds-times-1-plus-0.6-normalized-grade-over-one-minus-normalized;normalized-grade-at-least-0.995-reject;bounded-ccw-nonclosed-3to128|unbuildable-empty;city-road-continuous-points-inside-boundary;intercity-unclipped","cityField":"seeded-radial-terrain-contour-guide-v1","direction":"heading-dot-at-least-zero;interior-angle-at-least90deg;all-assembled-route-final-gate-v2","elevation":"relative-height-times-elevationScaleMeters-v1","limits":"maxGrade-roadWidthMeters-maxBridgeLengthMeters-maxTunnelLengthMeters-v1","parcelFace":"road-parcels-v4-boundary-highway;cityId-exact-arterial-local-street-surface-only;quantized-strict-xy-intersection-split;dcel-left-turn;positive-inside-concave-boundary;oriented-length-weighted-second-moment-principal-axis;canonical-longest-edge-isotropic-fallback;projection-midline-clip;area22500-recursion-depth8;inset-half-widest-road-plus-setback;triangulated-max-square-safe-bounds-v4","parcelFrontage":"face-plus-uncovered-frontage-v1;cityId-exact-arterial-local-street-surface-elementary-run;polyline-slice-16to42m;two-sided-offset;depth-clamp-blockSize-times-0.18-10to20;source-and-road-corridor-clear;face-first-frontage-positive-area-nonoverlap-stable-id-greedy-v1","parcelGraph":"road-parcels-v4-boundary-highway","parcelIdentity":"boundary-token-sorted-hash-worldSeed-citySeed-cityId;oriented-split-normal-token;frontage-side-and-ordinal;weighted-land-use;id-sort-v3","parcelTerrain":"polygon-touching-cells-dry-finite;adjacent-touching-cell-slope-at-most-settings-maxSlope;grid-at-most257-v1","portalLookahead":"complete-portal-before-partial-surface-v1;exact-dry-grid-portal-preserved-v1;off-grid-origin-requires-validated-surface-connector-v1;connector-budget-cost-required-v1","repair":"same-core-segment-splice;10m-grid;at-most8-attempts;min-margin200m-v1","roadClass":"required-kind-intercity-arterial-local;required-class-street-motorway;intercity-motorway-else-street;all-intercity-motorway-and-city-nonbuildable-roads-forbidden-corridor;centerline-no-intersection-or-containment;clearance-half-width-plus-setback-v1","shortcut":"surface-run-control-edge-boundaries;candidates-i-to-j-j-at-most-i-plus24-or-last;actual-sampler-water-grade-step-at-most10m;reverse-sparse-dag-heading-compatible-dot-epsilon1e-12;no-accumulated-cost;farthest-reachable-stable-descending;retain-original-if-no-complete-chain;whole-road-stable-branch-unreachable-if-final-acute;bridge-tunnel-excluded-v3","terrain":"canonical-plane-hydrology-fixed-sampling;global-long-axis257;city-long-axis65to257;actual-finite-sampler-step10m;no-sub10m-obstacle-guarantee-v1","tunnel":"covered-dry-portal-bore;actual-cover-at-least1m;3d-length-at-most-maxTunnelLengthMeters;no-shortcut-or-split;no-water-interior;roadWidth-surface-abutment-v2","version":6}';
7
+ /**
8
+ * 该字符串绑定 profile、算法版本与上方 canonical 规则字节的 SHA-256。
9
+ * 道路语义变化时必须发布新 identity,禁止让旧世界静默重算为不同结果。
10
+ */
11
+ export const LEGACY_V6_IDENTITY = "chat.worldengine.terrain-roads/v1;rules-sha256=9dc32e6e3f5e63fbf378d6b83dfa67c2e9d62dabfebe5b432956f7ff0fdb8443";
12
+ export const STRUCTURED_V8_ROAD_GENERATION_RULES_CANONICAL = '{"version":8,"algorithm":"direction-state-a-star-v2;32-coprime-neighbors;stable-heap-tie-order;route-edge-cache-v1","cityField":"structured-two-family-seeded-skeleton-v8;candidate-only-actual-terrain-router-required","cityCandidateBudget":"boundary-polygon-shoelace-abs-area-m2;ceil-sqrt-area-over-block-times-0.42-per-family;clamp6to15;not-nominal-radius-area;not-feasible-terrain-mask","cityCandidateFamilies":"six-arterial-rays-from-center-four-collinear-points;arterial-base-seeded-angle-plus-sixth-turn-plus-seeded-jitter;two-transverse-families-base-and-base-plus-pi-over-two-plus-seeded-0.18rad;collector-and-local;four-point-parabolic-sweeps;seeded-bend-block-times-0.32;actual-terrain-and-boundary-gates","cityBoundary":"radial-budget-v2;world-seed-city-seed-city-id-fnv1a-xor;24to128-rays;step-at-most10m;phase-smooth-three-harmonics-radius-0.85to1.15;actual-sampler-surface-or-complete-classify-edge-portal;surface-abs-grade-integral-ds-times-1-plus-0.6-normalized-grade-over-one-minus-normalized;normalized-grade-at-least-0.995-reject;bounded-ccw-nonclosed-3to128|unbuildable-empty;city-road-continuous-points-inside-boundary;intercity-unclipped","cityStructuredClip":"v8-nonarterial-all-exact-boundary-inside-runs;candidate-segment-boundary-intersections;boundary-inclusive;rooted-run-nearest-original-sweep-midpoint-else-inside-run-nearest-midpoint;arterial-uses-legacy-origin-first-exit-clip;final-route-sample-boundary-verify-at-most10m","cityStructuredRoot":"v8-transverse-same-city-surface-strict-internal-xy-intersection;parallel-collinear-endpoint-near-end-reject-epsilon1e-9;nearest-original-sweep-midpoint-then-stable-road-segment-point-pair-tie-order;root-z-actual-terrain-sample;both-old-surface-halves-revalidate-before-noding","cityRootArms":"root-left-right-independent-anchor-direct-or-bounded-astar-finish-and-boundary-check;both-concatenate|one-commit-valid-arm-and-record-other-unreachable|none-reject;assembled-root-route-no-acute-final-gate;preserve-root-xy","citySurfaceNoding":"v8-same-city-nonintercity-surface-only;strict-internal-xy-crossing-with-nonfinite-reject-and-dimensionless-interior-epsilon1e-9|positive-collinear-xy-overlap-line-distance-at-most1e-7;canonical-overlap-endpoints-xy-round-1e-7m-and-z-actual-terrain-sample;all-four-half-edges-or-local-endpoint-replacement-surface-revalidate;stable-road-segment-original-edge-index-descending-and-t-descending-insert-order;not-cross-city-bridge-tunnel-or-general-grade-separation","cityExactSurfaceReuse":"after-same-city-surface-noding-and-common-overlap-endpoint-rewrite;same-city-nonintercity-contiguous-all-surface-normalized-run-only-without-crossing-bridge-or-tunnel;undirected-exact-xyz-bit-elementary-key;arterial-then-local-then-lexical-road-id-owner;partial-overlap-reuse-removes-nonowner-exact-pieces-retains-continuous-chains;single-retained-chain-keeps-parent-id|multiple-retained-chains-child-id-parent-plus-retained-child-first-last-xy-IEEE-bits-and-reuse-purpose-no-ordinal;refresh-sorted-layout-ids;no-reuse-status-output;not-near-or-unvalidated-overlap-reuse","cityAccess":"legacy-v6-only:surface-street-node-short-connect-v1;radius-over-block-times-1.5-ceil-4to12;candidate-distance-0.75to3-block;target-1.7-block;stable-city-seed-node-pair-sort;surface-only-existing-nodes;actual-sampler-direct-or-bounded-astar;complete-portal-no-acute-boundary-containment;access-unreachable-domain-v1","parcelFace":"structured-v8-convex-closed-face-with-every-simplified-edge-matched-to-real-ordinary-street-elementary-frontage-only;per-edge-inward-half-plane-offset-before-split;clearance-max-matching-edge-half-width-plus-nonnegative-setback;mixed-width-collinear-match-uses-max-conservative-clearance;nonconvex-unmatched-or-invalid-offset-closed-face-reject-no-topology-guess","parcelSplit":"structured-v8-projection-midline-clip-area-settings-maxFaceAreaMeters-default22500-recursion-depth8;each-child-needs-longest-continuous-collinear-overlap-with-inset-real-street-frontage-at-least-max-10-min-20-widest-road;not-fragment-sum;on-failure-retain-parent-unsplit;cut-edge-is-not-frontage","parcelFrontage":"face-plus-uncovered-frontage-v1;open-area-only-real-surface-ordinary-street-segment-run;polyline-slice-min16-max42-except-unsplittable-first-edge-may-exceed42;two-sided-offset;inner-road-corridor-clearance-plus-0.01;source-run-clearance-recheck-at-least-clearance-minus0.2;depth-clamp-blockSize-times-0.18-10to20;source-and-road-corridor-clear;face-first-frontage-positive-area-nonoverlap-stable-id-greedy-v1;no-entrance-or-navigation-reachability-claim","legacyParcel":"legacy-v6-undefined-or-explicit-legacy-uses-prior-split-and-centroid-inset-path;v8-only-convex-offset-and-child-frontage-rule;shared-invalid-algorithm-fail-closed","parcelGraph":"road-parcels-v4-boundary-highway","parcelIdentity":"boundary-token-sorted-hash-worldSeed-citySeed-cityId;oriented-split-normal-token;frontage-side-and-ordinal;weighted-land-use;id-sort-v3","parcelTerrain":"polygon-touching-cells-dry-finite;adjacent-touching-cell-slope-at-most-settings-maxSlope;grid-at-most257-v1","roadClass":"required-kind-intercity-arterial-local;required-class-street-motorway;intercity-motorway-else-street;all-intercity-motorway-and-city-nonbuildable-roads-forbidden-corridor;centerline-no-intersection-or-containment;clearance-half-width-plus-setback-v1","direction":"heading-dot-at-least-zero;interior-angle-at-least90deg;all-assembled-route-final-gate-v2","limits":"maxGrade-roadWidthMeters-maxBridgeLengthMeters-maxTunnelLengthMeters-v1","elevation":"relative-height-times-elevationScaleMeters-v1","terrain":"canonical-plane-hydrology-fixed-sampling;global-long-axis257;city-long-axis65to257;actual-finite-sampler-step10m;no-sub10m-obstacle-guarantee-v1","portalLookahead":"complete-portal-before-partial-surface-v1;exact-dry-grid-portal-preserved-v1;off-grid-origin-requires-validated-surface-connector-v1;connector-budget-cost-required-v1","bridge":"complete-dry-portal-water-span-v1;linear-deck-3d-length-at-most-maxBridgeLengthMeters;all-water-interior;no-shortcut-or-split-v2","tunnel":"covered-dry-portal-bore;actual-cover-at-least1m;3d-length-at-most-maxTunnelLengthMeters;no-shortcut-or-split;no-water-interior;roadWidth-surface-abutment-v2","shortcut":"surface-run-control-edge-boundaries;candidates-i-to-j-j-at-most-i-plus24-or-last;actual-sampler-water-grade-step-at-most10m;reverse-sparse-dag-heading-compatible-dot-epsilon1e-12;no-accumulated-cost;farthest-reachable-stable-descending;retain-original-if-no-complete-chain;whole-road-stable-branch-unreachable-if-final-acute;bridge-tunnel-excluded-v3","repair":"same-core-segment-splice;10m-grid;at-most8-attempts;min-margin200m-v1"}';
13
+ export const STRUCTURED_V8_IDENTITY = "chat.worldengine.terrain-roads/v1;rules-sha256=03ab0544e8fdfc741045dccac18a946eb95b76bc10e9880012cba50060b29b4f";
14
+ export const FRONTAGE_BALANCED_V9_ROAD_GENERATION_RULES_CANONICAL = '{"version":9,"algorithm":"direction-state-a-star-v2;32-coprime-neighbors;stable-heap-tie-order;route-edge-cache-v1","cityField":"structured-two-family-seeded-skeleton-v8;candidate-only-actual-terrain-router-required","cityCandidateBudget":"boundary-polygon-shoelace-abs-area-m2;ceil-sqrt-area-over-block-times-0.42-per-family;clamp6to15;not-nominal-radius-area;not-feasible-terrain-mask","cityCandidateFamilies":"six-arterial-rays-from-center-four-collinear-points;arterial-base-seeded-angle-plus-sixth-turn-plus-seeded-jitter;two-transverse-families-base-and-base-plus-pi-over-two-plus-seeded-0.18rad;collector-and-local;four-point-parabolic-sweeps;seeded-bend-block-times-0.32;actual-terrain-and-boundary-gates","cityBoundary":"radial-budget-v2;world-seed-city-seed-city-id-fnv1a-xor;24to128-rays;step-at-most10m;phase-smooth-three-harmonics-radius-0.85to1.15;actual-sampler-surface-or-complete-classify-edge-portal;surface-abs-grade-integral-ds-times-1-plus-0.6-normalized-grade-over-one-minus-normalized;normalized-grade-at-least-0.995-reject;bounded-ccw-nonclosed-3to128|unbuildable-empty;city-road-continuous-points-inside-boundary;intercity-unclipped","cityStructuredClip":"v8-nonarterial-all-exact-boundary-inside-runs;candidate-segment-boundary-intersections;boundary-inclusive;rooted-run-nearest-original-sweep-midpoint-else-inside-run-nearest-midpoint;arterial-uses-legacy-origin-first-exit-clip;final-route-sample-boundary-verify-at-most10m","cityStructuredRoot":"v8-transverse-same-city-surface-strict-internal-xy-intersection;parallel-collinear-endpoint-near-end-reject-epsilon1e-9;nearest-original-sweep-midpoint-then-stable-road-segment-point-pair-tie-order;root-z-actual-terrain-sample;both-old-surface-halves-revalidate-before-noding","cityRootArms":"root-left-right-independent-anchor-direct-or-bounded-astar-finish-and-boundary-check;both-concatenate|one-commit-valid-arm-and-record-other-unreachable|none-reject;assembled-root-route-no-acute-final-gate;preserve-root-xy","citySurfaceNoding":"v8-same-city-nonintercity-surface-only;strict-internal-xy-crossing-with-nonfinite-reject-and-dimensionless-interior-epsilon1e-9|positive-collinear-xy-overlap-line-distance-at-most1e-7;canonical-overlap-endpoints-xy-round-1e-7m-and-z-actual-terrain-sample;all-four-half-edges-or-local-endpoint-replacement-surface-revalidate;stable-road-segment-original-edge-index-descending-and-t-descending-insert-order;not-cross-city-bridge-tunnel-or-general-grade-separation","cityExactSurfaceReuse":"after-same-city-surface-noding-and-common-overlap-endpoint-rewrite;same-city-nonintercity-contiguous-all-surface-normalized-run-only-without-crossing-bridge-or-tunnel;undirected-exact-xyz-bit-elementary-key;arterial-then-local-then-lexical-road-id-owner;partial-overlap-reuse-removes-nonowner-exact-pieces-retains-continuous-chains;single-retained-chain-keeps-parent-id|multiple-retained-chains-child-id-parent-plus-retained-child-first-last-xy-IEEE-bits-and-reuse-purpose-no-ordinal;refresh-sorted-layout-ids;no-reuse-status-output;not-near-or-unvalidated-overlap-reuse","cityAccess":"legacy-v6-only:surface-street-node-short-connect-v1;radius-over-block-times-1.5-ceil-4to12;candidate-distance-0.75to3-block;target-1.7-block;stable-city-seed-node-pair-sort;surface-only-existing-nodes;actual-sampler-direct-or-bounded-astar;complete-portal-no-acute-boundary-containment;access-unreachable-domain-v1","parcelAlgorithm":"identity-bound-v1;v6=legacy-v6-road-core-and-parcels;v8=structured-v8-road-core-and-parcels;v9=structured-v8-road-core-plus-frontage-balanced-v9-parcels;v9-vs-v8-selects-parcel-only;no-load-time-upgrade","parcelFace":"structured-v8-convex-closed-face-with-every-simplified-edge-matched-to-real-ordinary-street-elementary-frontage-only;per-edge-inward-half-plane-offset-before-split;clearance-max-matching-edge-half-width-plus-nonnegative-setback;mixed-width-collinear-match-uses-max-conservative-clearance;nonconvex-unmatched-or-invalid-offset-closed-face-reject-no-topology-guess","parcelSplit":"frontage-balanced-v9-primary-structured-v8-projection-midline-clip-area-settings-maxFaceAreaMeters-default22500;each-child-needs-longest-continuous-collinear-overlap-with-inset-real-street-frontage-at-least-max-10-min-20-widest-road;not-fragment-sum;when-primary-area-frontage-invalid-try-real-inset-frontage-overlap-cuts-length-desc-edge-id-normal-key;canonical-positive-frontage-tangent-normal;cut-overlap-midpoint-projection;dedup-normal-and-cut;first-area-frontage-valid-candidate;recursive-split-depth8;emitted-children-pass-existing-final-terrain-corridor-nonoverlap-gates;no-retry-after-final-rejection;on-all-area-frontage-failure-retain-parent-unsplit;cut-edge-is-not-frontage","parcelFrontage":"face-plus-uncovered-frontage-v1;open-area-only-real-surface-ordinary-street-segment-run;polyline-slice-min16-max42-except-unsplittable-first-edge-may-exceed42;two-sided-offset;inner-road-corridor-clearance-plus-0.01;source-run-clearance-recheck-at-least-clearance-minus0.2;depth-clamp-blockSize-times-0.18-10to20;source-and-road-corridor-clear;face-first-frontage-positive-area-nonoverlap-stable-id-greedy-v1;no-entrance-or-navigation-reachability-claim","legacyParcel":"legacy-v6-undefined-or-explicit-legacy-uses-prior-split-and-centroid-inset-path;structured-v8-uses-convex-offset-and-primary-child-frontage-rule;frontage-balanced-v9-keeps-v8-road-core-face-inset-and-primary-split-plus-stable-frontage-cut-fallback;shared-invalid-algorithm-fail-closed","parcelGraph":"road-parcels-v4-boundary-highway","parcelIdentity":"boundary-token-sorted-hash-worldSeed-citySeed-cityId;oriented-split-normal-token;frontage-side-and-ordinal;weighted-land-use;id-sort-v3","parcelTerrain":"polygon-touching-cells-dry-finite;adjacent-touching-cell-slope-at-most-settings-maxSlope;grid-at-most257-v1","roadClass":"required-kind-intercity-arterial-local;required-class-street-motorway;intercity-motorway-else-street;all-intercity-motorway-and-city-nonbuildable-roads-forbidden-corridor;centerline-no-intersection-or-containment;clearance-half-width-plus-setback-v1","direction":"heading-dot-at-least-zero;interior-angle-at-least90deg;all-assembled-route-final-gate-v2","limits":"maxGrade-roadWidthMeters-maxBridgeLengthMeters-maxTunnelLengthMeters-v1","elevation":"relative-height-times-elevationScaleMeters-v1","terrain":"canonical-plane-hydrology-fixed-sampling;global-long-axis257;city-long-axis65to257;actual-finite-sampler-step10m;no-sub10m-obstacle-guarantee-v1","portalLookahead":"complete-portal-before-partial-surface-v1;exact-dry-grid-portal-preserved-v1;off-grid-origin-requires-validated-surface-connector-v1;connector-budget-cost-required-v1","bridge":"complete-dry-portal-water-span-v1;linear-deck-3d-length-at-most-maxBridgeLengthMeters;all-water-interior;no-shortcut-or-split-v2","tunnel":"covered-dry-portal-bore;actual-cover-at-least1m;3d-length-at-most-maxTunnelLengthMeters;no-shortcut-or-split;no-water-interior;roadWidth-surface-abutment-v2","shortcut":"surface-run-control-edge-boundaries;candidates-i-to-j-j-at-most-i-plus24-or-last;actual-sampler-water-grade-step-at-most10m;reverse-sparse-dag-heading-compatible-dot-epsilon1e-12;no-accumulated-cost;farthest-reachable-stable-descending;retain-original-if-no-complete-chain;whole-road-stable-branch-unreachable-if-final-acute;bridge-tunnel-excluded-v3","repair":"same-core-segment-splice;10m-grid;at-most8-attempts;min-margin200m-v1"}';
15
+ export const FRONTAGE_BALANCED_V9_IDENTITY = "chat.worldengine.terrain-roads/v1;rules-sha256=671b01df50d378c85208f910ba10e63ff5b03d3787619898c8de60453329b38b";
16
+ export const ROAD_GENERATION_RULES_CANONICAL = '{"version":10,"algorithm":"direction-state-a-star-v2;32-coprime-neighbors;stable-heap-tie-order;route-edge-cache-v1","cityField":"structured-two-family-seeded-skeleton-v8;candidate-only-actual-terrain-router-required","cityCandidateBudget":"boundary-polygon-shoelace-abs-area-m2;ceil-sqrt-area-over-block-times-0.42-per-family;clamp6to15;not-nominal-radius-area;not-feasible-terrain-mask","cityCandidateFamilies":"six-arterial-rays-from-center-four-collinear-points;arterial-base-seeded-angle-plus-sixth-turn-plus-seeded-jitter;two-transverse-families-base-and-base-plus-pi-over-two-plus-seeded-0.18rad;collector-and-local;four-point-parabolic-sweeps;seeded-bend-block-times-0.32;actual-terrain-and-boundary-gates","cityBoundary":"radial-budget-v2;world-seed-city-seed-city-id-fnv1a-xor;24to128-rays;step-at-most10m;phase-smooth-three-harmonics-radius-0.85to1.15;actual-sampler-surface-or-complete-classify-edge-portal;surface-abs-grade-integral-ds-times-1-plus-0.6-normalized-grade-over-one-minus-normalized;normalized-grade-at-least-0.995-reject;bounded-ccw-nonclosed-3to128|unbuildable-empty;city-road-continuous-points-inside-boundary;intercity-unclipped","cityStructuredClip":"v8-nonarterial-all-exact-boundary-inside-runs;candidate-segment-boundary-intersections;boundary-inclusive;rooted-run-nearest-original-sweep-midpoint-else-inside-run-nearest-midpoint;arterial-uses-legacy-origin-first-exit-clip;final-route-sample-boundary-verify-at-most10m","cityStructuredRoot":"v8-transverse-same-city-surface-strict-internal-xy-intersection;parallel-collinear-endpoint-near-end-reject-epsilon1e-9;nearest-original-sweep-midpoint-then-stable-road-segment-point-pair-tie-order;root-z-actual-terrain-sample;both-old-surface-halves-revalidate-before-noding","cityRootArms":"root-left-right-independent-anchor-direct-or-bounded-astar-finish-and-boundary-check;both-concatenate|one-commit-valid-arm-and-record-other-unreachable|none-reject;assembled-root-route-no-acute-final-gate;preserve-root-xy","citySurfaceNoding":"v8-same-city-nonintercity-surface-only;strict-internal-xy-crossing-with-nonfinite-reject-and-dimensionless-interior-epsilon1e-9|positive-collinear-xy-overlap-line-distance-at-most1e-7;canonical-overlap-endpoints-xy-round-1e-7m-and-z-actual-terrain-sample;all-four-half-edges-or-local-endpoint-replacement-surface-revalidate;stable-road-segment-original-edge-index-descending-and-t-descending-insert-order;not-cross-city-bridge-tunnel-or-general-grade-separation","cityExactSurfaceReuse":"after-same-city-surface-noding-and-common-overlap-endpoint-rewrite;same-city-nonintercity-contiguous-all-surface-normalized-run-only-without-crossing-bridge-or-tunnel;undirected-exact-xyz-bit-elementary-key;arterial-then-local-then-lexical-road-id-owner;partial-overlap-reuse-removes-nonowner-exact-pieces-retains-continuous-chains;single-retained-chain-keeps-parent-id|multiple-retained-chains-child-id-parent-plus-retained-child-first-last-xy-IEEE-bits-and-reuse-purpose-no-ordinal;refresh-sorted-layout-ids;no-reuse-status-output;not-near-or-unvalidated-overlap-reuse","cityAccess":"legacy-v6-only:surface-street-node-short-connect-v1;radius-over-block-times-1.5-ceil-4to12;candidate-distance-0.75to3-block;target-1.7-block;stable-city-seed-node-pair-sort;surface-only-existing-nodes;actual-sampler-direct-or-bounded-astar;complete-portal-no-acute-boundary-containment;access-unreachable-domain-v1","parcelAlgorithm":"identity-bound-v1;v6=legacy-v6-road-core-and-parcels;v8=structured-v8-road-core-and-parcels;v9=structured-v8-road-core-plus-frontage-balanced-v9-parcels;v10=structured-v8-road-core-plus-shape-filled-v10-parcels;v10-vs-v9-selects-parcel-only;no-load-time-upgrade","parcelFace":"shape-filled-v10-simple-single-ring-closed-face;real-ordinary-street-elementary-frontage-only;collinear-ring-simplify;per-edge-inward-offset-max-matching-real-road-half-width-plus-nonnegative-setback-plus-4epsilon-quantization-guard;inset-must-stay-within-source-and-strict-road-clearance;self-cross-reject;concave-ear-clip-then-stable-convex-merge;internal-chords-have-no-offset-and-no-frontage;unsupported-complex-or-hole-face-reject-no-topology-guess","parcelSplit":"shape-filled-v10-long-axis-oriented-bounds-primary-then-stable-face-axis;projection-midline-clip-targets-settings-maxFaceAreaMeters-default22500-not-terminal-hard-limit;shape-context-cut-children-inset-by-4epsilon-per-side-leaving-8epsilon-artificial-nonroad-gap-to-prevent-quantized-shared-edge-positive-overlap;no-distance-or-overlap-gate-relaxation;both-children-area-at-least-settings-minParcelAreaMeters-default36;each-child-needs-longest-continuous-real-inset-street-frontage-at-least-max-10-min-20-widest-road;shape-node-and-recursive-output-hard-gates;pair-atomic-no-single-child-commit;frontage-balanced-real-inset-frontage-cut-fallback;recursive-depth8;at-depth-or-no-valid-cut-shape-valid-parent-may-remain-even-over-max-area;at-depth-or-no-valid-cut-invalid-shape-reject;cut-edge-is-not-frontage","parcelFrontage":"shape-filled-v10-face-first-then-uncovered-frontage-only;closed-valid-inset-faces-fill-before-open-street;real-surface-ordinary-street-run-resampled-at-at-most-min-10-maxSliceLength;two-sided-offset;depth-at-least-blockSize-times-0.18-and-at-least-minShortSide-times-sqrt2-plus1;maxSliceLength-max-requiredStripDimension-plus10-only-when-requiredStripDimension-over42-and-min-42-maxAspectRatio-times-depth-so-minShortSide-override-remains-sliceable;slice-at-least-minShortSide-times-sqrt2-plus1;shape-safe-bounds-and-ratio-hard-gates;source-and-all-road-corridor-boundary-terrain-clear;positive-area-nonoverlap-stable-id-greedy;no-entrance-or-navigation-reachability-claim","legacyParcel":"legacy-v6-undefined-or-explicit-legacy-uses-prior-split-and-centroid-inset-path;structured-v8-uses-convex-offset-and-primary-child-frontage-rule;frontage-balanced-v9-keeps-v8-road-core-face-inset-and-primary-split-plus-stable-frontage-cut-fallback;shape-filled-v10-keeps-v8-road-core-and-uses-simple-ring-inset-concave-decomposition-shape-hard-gates-and-uncovered-frontage-only;shared-invalid-algorithm-fail-closed","parcelGraph":"road-parcels-v4-boundary-highway","parcelIdentity":"boundary-token-sorted-hash-worldSeed-citySeed-cityId;oriented-split-normal-token;frontage-side-and-ordinal;weighted-land-use;id-sort-v3;shape-filled-v10-canonical-ring-ear-clip-first-valid-vertex-order-then-first-pair-convex-merge-loop;decomposed-piece-traversal-order-is-explicit-root-c-pieceIndex-and-affects-stable-id","parcelTerrain":"polygon-touching-cells-dry-finite;adjacent-touching-cell-slope-at-most-settings-maxSlope;grid-at-most257-v1","roadClass":"required-kind-intercity-arterial-local;required-class-street-motorway;intercity-motorway-else-street;all-intercity-motorway-and-city-nonbuildable-roads-forbidden-corridor;centerline-no-intersection-or-containment;clearance-half-width-plus-setback-v1","direction":"heading-dot-at-least-zero;interior-angle-at-least90deg;all-assembled-route-final-gate-v2","limits":"maxGrade-roadWidthMeters-maxBridgeLengthMeters-maxTunnelLengthMeters-v1","elevation":"relative-height-times-elevationScaleMeters-v1","terrain":"canonical-plane-hydrology-fixed-sampling;global-long-axis257;city-long-axis65to257;actual-finite-sampler-step10m;no-sub10m-obstacle-guarantee-v1","portalLookahead":"complete-portal-before-partial-surface-v1;exact-dry-grid-portal-preserved-v1;off-grid-origin-requires-validated-surface-connector-v1;connector-budget-cost-required-v1","bridge":"complete-dry-portal-water-span-v1;linear-deck-3d-length-at-most-maxBridgeLengthMeters;all-water-interior;no-shortcut-or-split-v2","tunnel":"covered-dry-portal-bore;actual-cover-at-least1m;3d-length-at-most-maxTunnelLengthMeters;no-shortcut-or-split;no-water-interior;roadWidth-surface-abutment-v2","shortcut":"surface-run-control-edge-boundaries;candidates-i-to-j-j-at-most-i-plus24-or-last;actual-sampler-water-grade-step-at-most10m;reverse-sparse-dag-heading-compatible-dot-epsilon1e-12;no-accumulated-cost;farthest-reachable-stable-descending;retain-original-if-no-complete-chain;whole-road-stable-branch-unreachable-if-final-acute;bridge-tunnel-excluded-v3","repair":"same-core-segment-splice;10m-grid;at-most8-attempts;min-margin200m-v1","parcelShape":"coordinates-round-decimal6-epsilon1e-6;minimum-oriented-convex-hull-edge-aligned-bounds;settings-maxAspectRatio-finite-at-least1-default4;settings-minShortSideMeters-finite-at-least26-default26;short-side-at-least-minShortSideMeters;long-side-at-most-short-side-times-maxAspectRatio;safe-axis-aligned-square-inside-polygon-width-and-height-at-least-minShortSideMeters;all-partition-nodes-and-emitted-parcels-terrain-boundary-corridor-clear"}';
17
+ export const ROAD_GENERATION_IDENTITY = "chat.worldengine.terrain-roads/v1;rules-sha256=58fc51cfe9986a8da0cc6931c8600cf4c1afbbcda80f58e00038b76f982aec5b";
18
+ /**
19
+ * 已发布 identity 的精确 allowlist。新算法必须先有冻结的 rules digest,才能加入这里;
20
+ * 不得以“当前默认值”替换已保存 source 的 identity。
21
+ */
22
+ export const SUPPORTED_ROAD_GENERATION_IDENTITIES = Object.freeze([
23
+ LEGACY_V6_IDENTITY,
24
+ STRUCTURED_V8_IDENTITY,
25
+ FRONTAGE_BALANCED_V9_IDENTITY,
26
+ ROAD_GENERATION_IDENTITY,
27
+ ]);
28
+ export function roadGenerationAlgorithm(identity) {
29
+ switch (identity) {
30
+ case LEGACY_V6_IDENTITY:
31
+ return "legacy-v6";
32
+ case STRUCTURED_V8_IDENTITY:
33
+ case FRONTAGE_BALANCED_V9_IDENTITY:
34
+ case ROAD_GENERATION_IDENTITY:
35
+ return "structured-v8";
36
+ }
37
+ }
38
+ /** 已保存 identity 独立选择 parcel 语义;V9 仍复用已发布 V8 道路 core。 */
39
+ export function roadParcelAlgorithm(identity) {
40
+ switch (identity) {
41
+ case LEGACY_V6_IDENTITY:
42
+ return "legacy-v6";
43
+ case STRUCTURED_V8_IDENTITY:
44
+ return "structured-v8";
45
+ case FRONTAGE_BALANCED_V9_IDENTITY:
46
+ return "frontage-balanced-v9";
47
+ case ROAD_GENERATION_IDENTITY:
48
+ return "shape-filled-v10";
49
+ }
50
+ }
51
+ /**
52
+ * 只有已冻结的后继 identity 才能令旧 source 出现显式升级预览入口。
53
+ * 加载或保存绝不能据此静默升级。
54
+ */
55
+ export function roadGenerationUpgradeTarget(identity) {
56
+ return identity === LEGACY_V6_IDENTITY
57
+ || identity === STRUCTURED_V8_IDENTITY
58
+ || identity === FRONTAGE_BALANCED_V9_IDENTITY
59
+ ? ROAD_GENERATION_IDENTITY
60
+ : undefined;
61
+ }
62
+ export const DEFAULT_ROAD_GENERATION = Object.freeze({
63
+ profile: ROAD_GENERATION_PROFILE,
64
+ identity: ROAD_GENERATION_IDENTITY,
65
+ allowBridges: true,
66
+ allowTunnels: false,
67
+ maxBridgeLengthMeters: 300,
68
+ maxTunnelLengthMeters: 1_000,
69
+ maxGrade: 0.15,
70
+ roadWidthMeters: 8,
71
+ elevationScaleMeters: 3_000,
72
+ });
73
+ const ROAD_GENERATION_KEYS = new Set([
74
+ "profile",
75
+ "identity",
76
+ "allowBridges",
77
+ "allowTunnels",
78
+ "maxBridgeLengthMeters",
79
+ "maxTunnelLengthMeters",
80
+ "maxGrade",
81
+ "roadWidthMeters",
82
+ "elevationScaleMeters",
83
+ ]);
84
+ function isRecord(value) {
85
+ return typeof value === "object" && value !== null && !Array.isArray(value);
86
+ }
87
+ function boundedNumber(value, field, minimum, maximum) {
88
+ if (typeof value !== "number" || !Number.isFinite(value))
89
+ throw new TypeError(`${field} 必须是有限数`);
90
+ if (value < minimum || value > maximum)
91
+ throw new RangeError(`${field} 必须位于 ${minimum}..${maximum}`);
92
+ return value;
93
+ }
94
+ function boolean(value, field) {
95
+ if (typeof value !== "boolean")
96
+ throw new TypeError(`${field} 必须是 boolean`);
97
+ return value;
98
+ }
99
+ function supportedIdentity(value) {
100
+ if (typeof value !== "string" || !SUPPORTED_ROAD_GENERATION_IDENTITIES.includes(value)) {
101
+ throw new TypeError(`identity 必须为 ${SUPPORTED_ROAD_GENERATION_IDENTITIES.join(" 或 ")}`);
102
+ }
103
+ return value;
104
+ }
105
+ /** 严格验证桥隧道路设置,拒绝未知字段并返回不可变 canonical 副本。 */
106
+ export function validateRoadGeneration(input) {
107
+ if (!isRecord(input))
108
+ throw new TypeError("RoadGenerationV1 必须是对象");
109
+ const unknown = Object.keys(input).filter((key) => !ROAD_GENERATION_KEYS.has(key));
110
+ if (unknown.length > 0)
111
+ throw new TypeError(`RoadGenerationV1 包含未知字段:${unknown.join(", ")}`);
112
+ const missing = [...ROAD_GENERATION_KEYS].filter((key) => !Object.hasOwn(input, key));
113
+ if (missing.length > 0)
114
+ throw new TypeError(`RoadGenerationV1 缺少字段:${missing.join(", ")}`);
115
+ if (input.profile !== ROAD_GENERATION_PROFILE)
116
+ throw new TypeError(`profile 必须为 ${ROAD_GENERATION_PROFILE}`);
117
+ const identity = supportedIdentity(input.identity);
118
+ return Object.freeze({
119
+ profile: ROAD_GENERATION_PROFILE,
120
+ identity,
121
+ allowBridges: boolean(input.allowBridges, "allowBridges"),
122
+ allowTunnels: boolean(input.allowTunnels, "allowTunnels"),
123
+ maxBridgeLengthMeters: boundedNumber(input.maxBridgeLengthMeters, "maxBridgeLengthMeters", 1, 1_000_000),
124
+ maxTunnelLengthMeters: boundedNumber(input.maxTunnelLengthMeters, "maxTunnelLengthMeters", 1, 1_000_000),
125
+ maxGrade: boundedNumber(input.maxGrade, "maxGrade", 0.01, 1),
126
+ roadWidthMeters: boundedNumber(input.roadWidthMeters, "roadWidthMeters", 3, 40),
127
+ elevationScaleMeters: boundedNumber(input.elevationScaleMeters, "elevationScaleMeters", 1, 100_000),
128
+ });
129
+ }