@hypersoniclabs/helix-cli 0.1.27-helix3.538 → 0.1.27-helix3.539

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.
Files changed (34) hide show
  1. package/dist/city/colliders/apply.d.ts +34 -0
  2. package/dist/city/colliders/apply.js +167 -0
  3. package/dist/city/colliders/apply.js.map +1 -0
  4. package/dist/city/colliders/buildingBoxes.d.ts +71 -0
  5. package/dist/city/colliders/buildingBoxes.js +214 -0
  6. package/dist/city/colliders/buildingBoxes.js.map +1 -0
  7. package/dist/city/colliders/command.d.ts +2 -0
  8. package/dist/city/colliders/command.js +46 -0
  9. package/dist/city/colliders/command.js.map +1 -0
  10. package/dist/city/colliders/deckColliders.d.ts +64 -0
  11. package/dist/city/colliders/deckColliders.js +263 -0
  12. package/dist/city/colliders/deckColliders.js.map +1 -0
  13. package/dist/city/colliders/glbBounds.d.ts +37 -0
  14. package/dist/city/colliders/glbBounds.js +84 -0
  15. package/dist/city/colliders/glbBounds.js.map +1 -0
  16. package/dist/index.js +6 -4
  17. package/dist/index.js.map +1 -1
  18. package/dist/tsconfig.build.tsbuildinfo +1 -1
  19. package/package.json +1 -1
  20. package/plugins/beamng-vehicle/bin/__pycache__/beamng_abs.cpython-312.pyc +0 -0
  21. package/plugins/beamng-vehicle/bin/__pycache__/beamng_audio.cpython-312.pyc +0 -0
  22. package/plugins/beamng-vehicle/bin/__pycache__/beamng_engine.cpython-312.pyc +0 -0
  23. package/plugins/beamng-vehicle/bin/__pycache__/beamng_expression.cpython-312.pyc +0 -0
  24. package/plugins/beamng-vehicle/bin/__pycache__/beamng_jbeam.cpython-312.pyc +0 -0
  25. package/plugins/beamng-vehicle/bin/__pycache__/beamng_materials.cpython-312.pyc +0 -0
  26. package/plugins/beamng-vehicle/bin/__pycache__/beamng_stock_events.cpython-312.pyc +0 -0
  27. package/plugins/beamng-vehicle/bin/__pycache__/fmod_studio.cpython-312.pyc +0 -0
  28. package/plugins/beamng-vehicle/bin/__pycache__/fsb5.cpython-312.pyc +0 -0
  29. package/plugins/beamng-vehicle/bin/__pycache__/sim_audio.cpython-312.pyc +0 -0
  30. package/plugins/beamng-vehicle/bin/__pycache__/sim_audio_ac.cpython-312.pyc +0 -0
  31. package/plugins/beamng-vehicle/bin/__pycache__/sim_audio_beamng.cpython-312.pyc +0 -0
  32. package/plugins/beamng-vehicle/bin/__pycache__/sim_audio_fixtures.cpython-312.pyc +0 -0
  33. package/plugins/beamng-vehicle/bin/__pycache__/test_beamng_engine.cpython-312.pyc +0 -0
  34. package/plugins/beamng-vehicle/bin/__pycache__/test_sim_audio.cpython-312.pyc +0 -0
@@ -0,0 +1,34 @@
1
+ import { type BuildingColliderOptions } from './buildingBoxes';
2
+ import { type DeckColliderOptions } from './deckColliders';
3
+ export interface PrefixSource {
4
+ read(path: string): Promise<Uint8Array>;
5
+ readRange(path: string, offset: number, length: number): Promise<Uint8Array>;
6
+ }
7
+ export declare function prefixSource(base: string): PrefixSource;
8
+ /** A 1 m unit cube centred on the origin: the one mesh every building box scales, rotates and places. */
9
+ export declare function unitBoxGlb(): Promise<Uint8Array>;
10
+ export interface ApplyOptions {
11
+ source: PrefixSource;
12
+ /** The root's folder name under `scene/`. */
13
+ rootName: string;
14
+ /** The folder name the new root is written as. */
15
+ newRootName: string;
16
+ buildings: Partial<BuildingColliderOptions> & {
17
+ enabled: boolean;
18
+ };
19
+ decks: Partial<DeckColliderOptions> & {
20
+ enabled: boolean;
21
+ roadCellM: number;
22
+ };
23
+ log: (message: string) => void;
24
+ concurrency?: number;
25
+ }
26
+ export interface ApplyResult {
27
+ files: Array<{
28
+ path: string;
29
+ bytes: Uint8Array;
30
+ }>;
31
+ report: Record<string, unknown>;
32
+ }
33
+ export declare function applyColliders(options: ApplyOptions): Promise<ApplyResult>;
34
+ export declare function writeFiles(out: string, files: ApplyResult['files']): Promise<void>;
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ // `helix city colliders apply`: completes the collision of a published city Scene without touching the data it ships.
3
+ //
4
+ // - elevated decks, ramps and rails: additional collider cells from the render tier (deckColliders.ts)
5
+ // - buildings: a collider-only child Scene of oriented boxes (buildingBoxes.ts), mounted by the root
6
+ //
7
+ // Reads the root and everything it needs from a data prefix (an https origin or a folder) and writes ONLY the new objects,
8
+ // in the prefix's own layout, to --out: the new root folder (the old root's document, resealed, plus its pin), the new
9
+ // deck-collider cells beside it, and the child Scene's folder. Everything else the new root points at is referenced by the same
10
+ // relative paths, so uploading --out next to a copy of the old root folder is the whole publication.
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.prefixSource = prefixSource;
13
+ exports.unitBoxGlb = unitBoxGlb;
14
+ exports.applyColliders = applyColliders;
15
+ exports.writeFiles = writeFiles;
16
+ const promises_1 = require("node:fs/promises");
17
+ const node_path_1 = require("node:path");
18
+ const node_crypto_1 = require("node:crypto");
19
+ const core_1 = require("@gltf-transform/core");
20
+ const helix_manifest_1 = require("@hypersoniclabs/helix-manifest");
21
+ const glbBounds_1 = require("./glbBounds");
22
+ const buildingBoxes_1 = require("./buildingBoxes");
23
+ const deckColliders_1 = require("./deckColliders");
24
+ function prefixSource(base) {
25
+ if (/^https?:\/\//.test(base)) {
26
+ const url = (path) => `${base.replace(/\/$/, '')}/${path}`;
27
+ const headers = { 'user-agent': 'Mozilla/5.0 helix-cli' };
28
+ const get = async (path, extra = {}) => {
29
+ for (let attempt = 0;; attempt += 1) {
30
+ try {
31
+ const response = await fetch(url(path), { headers: { ...headers, ...extra } });
32
+ if (!response.ok && response.status !== 206)
33
+ throw new Error(`${response.status} ${url(path)}`);
34
+ return new Uint8Array(await response.arrayBuffer());
35
+ }
36
+ catch (error) {
37
+ if (attempt >= 4)
38
+ throw error;
39
+ await new Promise((r) => setTimeout(r, 500 * (attempt + 1)));
40
+ }
41
+ }
42
+ };
43
+ return { read: (path) => get(path), readRange: (path, offset, length) => get(path, { range: `bytes=${offset}-${offset + length - 1}` }) };
44
+ }
45
+ return {
46
+ read: async (path) => new Uint8Array(await (0, promises_1.readFile)((0, node_path_1.join)(base, path))),
47
+ readRange: async (path, offset, length) => new Uint8Array((await (0, promises_1.readFile)((0, node_path_1.join)(base, path))).subarray(offset, offset + length)),
48
+ };
49
+ }
50
+ /** A 1 m unit cube centred on the origin: the one mesh every building box scales, rotates and places. */
51
+ async function unitBoxGlb() {
52
+ const document = new core_1.Document();
53
+ const buffer = document.createBuffer();
54
+ const h = 0.5;
55
+ const corners = [[-h, -h, -h], [h, -h, -h], [h, h, -h], [-h, h, -h], [-h, -h, h], [h, -h, h], [h, h, h], [-h, h, h]].flat();
56
+ // Counter-clockwise outward faces.
57
+ const quads = [[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [3, 7, 6, 2], [0, 4, 7, 3], [1, 2, 6, 5]];
58
+ const indices = quads.flatMap(([a, b, c, d]) => [a, b, c, a, c, d]);
59
+ const position = document.createAccessor().setType('VEC3').setArray(new Float32Array(corners)).setBuffer(buffer);
60
+ const index = document.createAccessor().setType('SCALAR').setArray(new Uint16Array(indices)).setBuffer(buffer);
61
+ const mesh = document.createMesh('unit-box').addPrimitive(document.createPrimitive().setAttribute('POSITION', position).setIndices(index));
62
+ document.createScene('unit-box').addChild(document.createNode('unit-box').setMesh(mesh));
63
+ return new core_1.NodeIO().writeBinary(document);
64
+ }
65
+ const sha256 = (bytes) => (0, node_crypto_1.createHash)('sha256').update(bytes).digest('hex');
66
+ const json = (value) => new TextEncoder().encode(JSON.stringify(value));
67
+ async function pool(items, size, work) {
68
+ const out = new Array(items.length);
69
+ let next = 0;
70
+ await Promise.all(Array.from({ length: Math.min(size, items.length) }, async () => {
71
+ for (let at = next++; at < items.length; at = next++)
72
+ out[at] = await work(items[at]);
73
+ }));
74
+ return out;
75
+ }
76
+ async function applyColliders(options) {
77
+ const { source, log } = options;
78
+ const concurrency = options.concurrency ?? 24;
79
+ const rootPath = `scene/${options.rootName}/scene.helix-scene.json`;
80
+ const root = JSON.parse(new TextDecoder().decode(await source.read(rootPath)));
81
+ const files = [];
82
+ const report = { root: options.rootName, newRoot: options.newRootName, rootRevision: root.revision };
83
+ let next = root;
84
+ if (options.decks.enabled) {
85
+ const resources = root.resources.filter((resource) => resource.kind === 'model' || resource.kind === 'collider');
86
+ const under = (dir) => resources.map((resource) => resource.source.uri ?? '').filter((uri) => uri.startsWith(dir)).sort();
87
+ const roads = {
88
+ cellSizeM: options.decks.roadCellM,
89
+ originX: root.terrain.kind === 'heightfield' ? root.terrain.grid.originX : 0,
90
+ originZ: root.terrain.kind === 'heightfield' ? root.terrain.grid.originZ : 0,
91
+ render: under('roads/render/'),
92
+ collision: under('roads/collider/'),
93
+ read: (path) => source.read(`scene/${options.rootName}/${path}`),
94
+ };
95
+ log(`decks: ${roads.render.length} render cells, ${roads.collision.length} collider cells, origin ${roads.originX},${roads.originZ}, cell ${roads.cellSizeM} m`);
96
+ const { cells, report: deck } = await (0, deckColliders_1.buildDeckColliders)(roads, { ...options.decks, log });
97
+ for (const cell of cells)
98
+ files.push({ path: `scene/${options.newRootName}/roads/${cell.file}`, bytes: cell.bytes });
99
+ next = (0, deckColliders_1.patchSceneDeckColliders)(next, cells, 'roads').scene;
100
+ report.decks = deck;
101
+ }
102
+ if (options.buildings.enabled) {
103
+ const mountIds = (next.mounts ?? []).map((mount) => mount);
104
+ const parts = [];
105
+ const boundsBySha = new Map();
106
+ for (const mount of mountIds) {
107
+ const folder = `scene/${mount.integrity.sha256}`;
108
+ const part = JSON.parse(new TextDecoder().decode(await source.read(`${folder}/scene.helix-scene.json`)));
109
+ const wanted = part.nodes.filter((node) => node.resource && node.components?.some((c) => c.type === 'render.mesh')).map((node) => node.resource);
110
+ const resourceIds = [...new Set(wanted)];
111
+ const byId = new Map(part.resources.map((resource) => [resource.id, resource]));
112
+ const bounds = new Map();
113
+ await pool(resourceIds, concurrency, async (id) => {
114
+ const resource = byId.get(id);
115
+ const uri = resource?.source?.uri;
116
+ if (!resource || !uri || resource.kind !== 'model')
117
+ return;
118
+ const key = `${resource.integrity.sha256}`;
119
+ let box = boundsBySha.get(key);
120
+ if (!box) {
121
+ box = await (0, glbBounds_1.glbBounds)((offset, length) => source.readRange(`${folder}/${uri}`, offset, length));
122
+ boundsBySha.set(key, box);
123
+ }
124
+ bounds.set(id, box);
125
+ });
126
+ log(`buildings: mount ${mount.id} -> ${part.nodes.length} nodes, ${bounds.size}/${resourceIds.length} model bounds`);
127
+ parts.push({ part, bounds });
128
+ }
129
+ const unit = await unitBoxGlb();
130
+ const unitSha = sha256(unit);
131
+ const unitUri = `colliders/unit-box.${unitSha.slice(0, 16)}.glb`;
132
+ const planOptions = { ...buildingBoxes_1.DEFAULT_BUILDING_COLLIDER_OPTIONS, ...options.buildings };
133
+ const { boxes, stats } = (0, buildingBoxes_1.planBuildingBoxes)(parts, planOptions);
134
+ const { scene: childUnsealed, stats: sets } = (0, buildingBoxes_1.buildColliderScene)(boxes, {
135
+ ...planOptions, unitBox: { sha256: unitSha, bytes: unit.length, uri: unitUri }, adapters: root.adapters,
136
+ });
137
+ const child = (0, buildingBoxes_1.sealScene)(childUnsealed);
138
+ const checked = (0, helix_manifest_1.validateSceneDocument)(child);
139
+ if (!checked.valid)
140
+ throw new Error(`the collider child does not validate: ${checked.errors.slice(0, 5).join('; ')}`);
141
+ const childBytes = json(child);
142
+ files.push({ path: `scene/${child.integrity.sha256}/scene.helix-scene.json`, bytes: childBytes });
143
+ files.push({ path: `scene/${child.integrity.sha256}/${unitUri}`, bytes: unit });
144
+ next = (0, buildingBoxes_1.mountColliderChild)(next, child);
145
+ report.buildings = { ...stats, ...sets, childSha256: child.integrity.sha256, childBytes: childBytes.length, unitBox: buildingBoxes_1.UNIT_BOX_RESOURCE_ID, streamRadiusM: planOptions.streamRadiusM };
146
+ }
147
+ next = (0, buildingBoxes_1.sealScene)(next);
148
+ const checked = (0, helix_manifest_1.validateSceneDocument)(next);
149
+ if (!checked.valid)
150
+ throw new Error(`the patched root does not validate: ${checked.errors.slice(0, 5).join('; ')}`);
151
+ const rootBytes = json(next);
152
+ files.push({ path: `scene/${options.newRootName}/scene.helix-scene.json`, bytes: rootBytes });
153
+ const pinOld = JSON.parse(new TextDecoder().decode(await source.read(`scene/${options.rootName}/pin.json`)));
154
+ files.push({ path: `scene/${options.newRootName}/pin.json`, bytes: json({ ...pinOld, revision: next.revision, integrity: { sha256: next.integrity.sha256 } }) });
155
+ report.newRootRevision = next.revision;
156
+ report.newRootSha256 = next.integrity.sha256;
157
+ report.newRootBytes = rootBytes.length;
158
+ return { files, report };
159
+ }
160
+ async function writeFiles(out, files) {
161
+ for (const file of files) {
162
+ const target = (0, node_path_1.join)(out, file.path);
163
+ await (0, promises_1.mkdir)((0, node_path_1.dirname)(target), { recursive: true });
164
+ await (0, promises_1.writeFile)(target, file.bytes);
165
+ }
166
+ }
167
+ //# sourceMappingURL=apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../../src/city/colliders/apply.ts"],"names":[],"mappings":";AAAA,sHAAsH;AACtH,EAAE;AACF,yGAAyG;AACzG,uGAAuG;AACvG,EAAE;AACF,2HAA2H;AAC3H,uHAAuH;AACvH,gIAAgI;AAChI,qGAAqG;;AAmBrG,oCAmBC;AAGD,gCAaC;AA+BD,wCA+EC;AAED,gCAMC;AA1KD,+CAA8D;AAC9D,yCAA0C;AAC1C,6CAAyC;AACzC,+CAAwD;AACxD,mEAA0F;AAC1F,2CAAmD;AACnD,mDAGyB;AACzB,mDAA6H;AAO7H,SAAgB,YAAY,CAAC,IAAY;IACvC,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;QAC3E,MAAM,OAAO,GAAG,EAAE,YAAY,EAAE,uBAAuB,EAAE,CAAC;QAC1D,MAAM,GAAG,GAAG,KAAK,EAAE,IAAY,EAAE,QAAgC,EAAE,EAAuB,EAAE;YAC1F,KAAK,IAAI,OAAO,GAAG,CAAC,GAAI,OAAO,IAAI,CAAC,EAAE,CAAC;gBACrC,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,CAAC,CAAC;oBAC/E,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;wBAAE,MAAM,IAAI,KAAK,CAAC,GAAG,QAAQ,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBAChG,OAAO,IAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;gBACtD,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBAAC,IAAI,OAAO,IAAI,CAAC;wBAAE,MAAM,KAAK,CAAC;oBAAC,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBAAC,CAAC;YAClH,CAAC;QACH,CAAC,CAAC;QACF,OAAO,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,MAAM,IAAI,MAAM,GAAG,MAAM,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IAC5I,CAAC;IACD,OAAO;QACL,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,UAAU,CAAC,MAAM,IAAA,mBAAQ,EAAC,IAAA,gBAAI,EAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACtE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,IAAI,UAAU,CAAC,CAAC,MAAM,IAAA,mBAAQ,EAAC,IAAA,gBAAI,EAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;KAChI,CAAC;AACJ,CAAC;AAED,yGAAyG;AAClG,KAAK,UAAU,UAAU;IAC9B,MAAM,QAAQ,GAAG,IAAI,eAAQ,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAC;IACvC,MAAM,CAAC,GAAG,GAAG,CAAC;IACd,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5H,mCAAmC;IACnC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACnG,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACpE,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACjH,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC/G,MAAM,IAAI,GAAG,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IAC3I,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACzF,OAAO,IAAI,aAAM,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;AAC5C,CAAC;AAmBD,MAAM,MAAM,GAAG,CAAC,KAAiB,EAAU,EAAE,CAAC,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC/F,MAAM,IAAI,GAAG,CAAC,KAAc,EAAc,EAAE,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;AAE7F,KAAK,UAAU,IAAI,CAAO,KAAmB,EAAE,IAAY,EAAE,IAA6B;IACxF,MAAM,GAAG,GAAG,IAAI,KAAK,CAAI,KAAK,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,IAAI,EAAE;QAChF,KAAK,IAAI,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE;YAAE,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IACxF,CAAC,CAAC,CAAC,CAAC;IACJ,OAAO,GAAG,CAAC;AACb,CAAC;AAEM,KAAK,UAAU,cAAc,CAAC,OAAqB;IACxD,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IAChC,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC;IAC9C,MAAM,QAAQ,GAAG,SAAS,OAAO,CAAC,QAAQ,yBAAyB,CAAC;IACpE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAiB,CAAC;IAC/F,MAAM,KAAK,GAAyB,EAAE,CAAC;IACvC,MAAM,MAAM,GAA4B,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,WAAW,EAAE,YAAY,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC9H,IAAI,IAAI,GAAiB,IAAI,CAAC;IAE9B,IAAI,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,KAAK,OAAO,IAAI,QAAQ,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;QACjH,MAAM,KAAK,GAAG,CAAC,GAAW,EAAY,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAE,QAAQ,CAAC,MAA2B,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAClK,MAAM,KAAK,GAAmB;YAC5B,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,SAAS;YAClC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC,CAAE,IAAI,CAAC,OAAyC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC/G,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC,CAAE,IAAI,CAAC,OAAyC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC/G,MAAM,EAAE,KAAK,CAAC,eAAe,CAAC;YAC9B,SAAS,EAAE,KAAK,CAAC,iBAAiB,CAAC;YACnC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,OAAO,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC;SACjE,CAAC;QACF,GAAG,CAAC,UAAU,KAAK,CAAC,MAAM,CAAC,MAAM,kBAAkB,KAAK,CAAC,SAAS,CAAC,MAAM,2BAA2B,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,UAAU,KAAK,CAAC,SAAS,IAAI,CAAC,CAAC;QACjK,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAA,kCAAkB,EAAC,KAAK,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3F,KAAK,MAAM,IAAI,IAAI,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,OAAO,CAAC,WAAW,UAAU,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QACrH,IAAI,GAAG,IAAA,uCAAuB,EAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC;QAC3D,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,IAAI,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;QAC3D,MAAM,KAAK,GAA6D,EAAE,CAAC;QAC3E,MAAM,WAAW,GAAG,IAAI,GAAG,EAAgB,CAAC;QAC5C,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAG,SAAS,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;YACjD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,yBAAyB,CAAC,CAAC,CAAiB,CAAC;YACzH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAS,CAAC,CAAC;YAClJ,MAAM,WAAW,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;YACzC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAU,CAAC,CAAC,CAAC;YACzF,MAAM,MAAM,GAAG,IAAI,GAAG,EAAgB,CAAC;YACvC,MAAM,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;gBAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC9B,MAAM,GAAG,GAAI,QAAQ,EAAE,MAAuC,EAAE,GAAG,CAAC;gBACpE,IAAI,CAAC,QAAQ,IAAI,CAAC,GAAG,IAAI,QAAQ,CAAC,IAAI,KAAK,OAAO;oBAAE,OAAO;gBAC3D,MAAM,GAAG,GAAG,GAAG,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;gBAC3C,IAAI,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;oBAAC,GAAG,GAAG,MAAM,IAAA,qBAAS,EAAC,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,MAAM,IAAI,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;oBAAC,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBAAC,CAAC;gBACzI,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YACtB,CAAC,CAAC,CAAC;YACH,GAAG,CAAC,oBAAoB,KAAK,CAAC,EAAE,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,WAAW,MAAM,CAAC,IAAI,IAAI,WAAW,CAAC,MAAM,eAAe,CAAC,CAAC;YACrH,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAC/B,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,UAAU,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,OAAO,GAAG,sBAAsB,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC;QACjE,MAAM,WAAW,GAAG,EAAE,GAAG,iDAAiC,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;QACnF,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAA,iCAAiB,EAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QAC/D,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,IAAA,kCAAkB,EAAC,KAAK,EAAE;YACtE,GAAG,WAAW,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxG,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,IAAA,yBAAS,EAAC,aAAa,CAAC,CAAC;QACvC,MAAM,OAAO,GAAG,IAAA,sCAAqB,EAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACtH,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,KAAK,CAAC,SAAS,CAAC,MAAM,yBAAyB,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;QAClG,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,KAAK,CAAC,SAAS,CAAC,MAAM,IAAI,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAChF,IAAI,GAAG,IAAA,kCAAkB,EAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACvC,MAAM,CAAC,SAAS,GAAG,EAAE,GAAG,KAAK,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,oCAAoB,EAAE,aAAa,EAAE,WAAW,CAAC,aAAa,EAAE,CAAC;IACxL,CAAC;IAED,IAAI,GAAG,IAAA,yBAAS,EAAC,IAAI,CAAC,CAAC;IACvB,MAAM,OAAO,GAAG,IAAA,sCAAqB,EAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,CAAC,OAAO,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpH,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,OAAO,CAAC,WAAW,yBAAyB,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IAC9F,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,OAAO,CAAC,QAAQ,WAAW,CAAC,CAAC,CAA4B,CAAC;IACxI,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,OAAO,CAAC,WAAW,WAAW,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;IACjK,MAAM,CAAC,eAAe,GAAG,IAAI,CAAC,QAAQ,CAAC;IACvC,MAAM,CAAC,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;IAC7C,MAAM,CAAC,YAAY,GAAG,SAAS,CAAC,MAAM,CAAC;IACvC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC;AAEM,KAAK,UAAU,UAAU,CAAC,GAAW,EAAE,KAA2B;IACvE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAA,gBAAI,EAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,IAAA,gBAAK,EAAC,IAAA,mBAAO,EAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,MAAM,IAAA,oBAAS,EAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;AACH,CAAC"}
@@ -0,0 +1,71 @@
1
+ import type { HelixSceneV2, SceneNode } from '@hypersoniclabs/helix-manifest';
2
+ import type { Box3 } from './glbBounds';
3
+ export declare const COLLIDER_CHILD_ID = "scene.city.building-colliders";
4
+ export declare const UNIT_BOX_RESOURCE_ID = "res.collider.unit-box";
5
+ export interface BuildingColliderOptions {
6
+ /** Metres around the player within which colliders are resident (the child's `streamRadiusM`). */
7
+ streamRadiusM: number;
8
+ /** Buildings per spatial block (one collision set, one stream group). Raised when the city would need more than `maxSets`. */
9
+ buildingsPerBlock: number;
10
+ maxSets: number;
11
+ /** Models smaller than this (footprint m2, or height m) are props, not buildings, and are left non-solid. */
12
+ minFootprintM2: number;
13
+ minHeightM: number;
14
+ /** The unit cube collider resource, already hashed and addressed by the caller. */
15
+ unitBox: {
16
+ sha256: string;
17
+ bytes: number;
18
+ uri: string;
19
+ };
20
+ adapters: HelixSceneV2['adapters'];
21
+ title?: string;
22
+ /** Skip instances whose resource id starts with one of these (e.g. trees) - rarely needed; models carry the filter in their bounds. */
23
+ skipResource?: (resourceId: string) => boolean;
24
+ }
25
+ export declare const DEFAULT_BUILDING_COLLIDER_OPTIONS: Readonly<{
26
+ streamRadiusM: 120;
27
+ buildingsPerBlock: 60;
28
+ maxSets: 240;
29
+ minFootprintM2: 4;
30
+ minHeightM: 2;
31
+ }>;
32
+ export interface PlannedBox {
33
+ id: string;
34
+ position: [number, number, number];
35
+ rotation: [number, number, number, number];
36
+ scale: [number, number, number];
37
+ /** World AABB of the oriented box. */
38
+ min: [number, number, number];
39
+ max: [number, number, number];
40
+ source: string;
41
+ }
42
+ export interface BoxPlanStats {
43
+ instances: number;
44
+ boxes: number;
45
+ skippedSmall: number;
46
+ skippedNoBounds: number;
47
+ sets: number;
48
+ maxPerSet: number;
49
+ }
50
+ /** The box of one placed model: the node's transform applied to the model's local AABB. */
51
+ export declare function boxOfNode(node: SceneNode, bounds: Box3, id: string): PlannedBox;
52
+ /** Median-split the boxes on the longer horizontal side until each block holds at most `perBlock`. */
53
+ export declare function splitBlocks(boxes: readonly PlannedBox[], perBlock: number): PlannedBox[][];
54
+ export declare function planBuildingBoxes(parts: ReadonlyArray<{
55
+ part: HelixSceneV2;
56
+ bounds: ReadonlyMap<string, Box3>;
57
+ }>, options: Pick<BuildingColliderOptions, 'minFootprintM2' | 'minHeightM' | 'skipResource'>): {
58
+ boxes: PlannedBox[];
59
+ stats: Pick<BoxPlanStats, 'instances' | 'boxes' | 'skippedSmall' | 'skippedNoBounds'>;
60
+ };
61
+ export declare function buildColliderScene(boxes: readonly PlannedBox[], options: BuildingColliderOptions): {
62
+ scene: HelixSceneV2;
63
+ stats: BoxPlanStats;
64
+ };
65
+ /** The sealing order every Scene v2 builder uses: revision = first 16 hex of the digest with revision and integrity zeroed. */
66
+ export declare function sealScene<T extends HelixSceneV2>(scene: T): T;
67
+ /**
68
+ * Mounts the collider child in a root document: the mount definition, the node that places it in the root's eager city group
69
+ * (so it is resident whenever the city is), and the group's declared memory. Returns a new, resealed root.
70
+ */
71
+ export declare function mountColliderChild(root: HelixSceneV2, child: HelixSceneV2, budgetMiB?: number): HelixSceneV2;
@@ -0,0 +1,214 @@
1
+ "use strict";
2
+ // Solid buildings for a city whose buildings are instanced models (a CS2 capture, any `granit-city` style composition): one
3
+ // oriented box per instance, taken from the model's own bounding box, carried as a small collider-only child Scene that the
4
+ // root mounts. The child exists because a Scene v2 document may carry 256 collision sets and a set belongs to exactly one
5
+ // node, while a stream group's reach is the profile's radius: a mounted child has its OWN profile, so the physics radius
6
+ // (colliders live 120 m around the player) is decoupled from the visual one (a kilometre of skyline) and phone memory and CPU
7
+ // stay flat however large the city is. Colliders are streamed in spatial blocks of ~60 buildings.
8
+ //
9
+ // A box is a `convex` collider over one shared unit-cube collider resource with a per-collider transform
10
+ // (position, rotation, scale), so a building is ~150 bytes of JSON and no per-building geometry exists anywhere.
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.DEFAULT_BUILDING_COLLIDER_OPTIONS = exports.UNIT_BOX_RESOURCE_ID = exports.COLLIDER_CHILD_ID = void 0;
13
+ exports.boxOfNode = boxOfNode;
14
+ exports.splitBlocks = splitBlocks;
15
+ exports.planBuildingBoxes = planBuildingBoxes;
16
+ exports.buildColliderScene = buildColliderScene;
17
+ exports.sealScene = sealScene;
18
+ exports.mountColliderChild = mountColliderChild;
19
+ const helix_manifest_1 = require("@hypersoniclabs/helix-manifest");
20
+ exports.COLLIDER_CHILD_ID = 'scene.city.building-colliders';
21
+ exports.UNIT_BOX_RESOURCE_ID = 'res.collider.unit-box';
22
+ exports.DEFAULT_BUILDING_COLLIDER_OPTIONS = Object.freeze({
23
+ streamRadiusM: 120,
24
+ buildingsPerBlock: 60,
25
+ maxSets: 240,
26
+ minFootprintM2: 4,
27
+ minHeightM: 2,
28
+ });
29
+ const round = (value, places) => Math.round(value * 10 ** places) / 10 ** places;
30
+ function rotate(q, v) {
31
+ const [x, y, z, w] = q;
32
+ const tx = 2 * (y * v[2] - z * v[1]);
33
+ const ty = 2 * (z * v[0] - x * v[2]);
34
+ const tz = 2 * (x * v[1] - y * v[0]);
35
+ return [v[0] + w * tx + (y * tz - z * ty), v[1] + w * ty + (z * tx - x * tz), v[2] + w * tz + (x * ty - y * tx)];
36
+ }
37
+ /** The box of one placed model: the node's transform applied to the model's local AABB. */
38
+ function boxOfNode(node, bounds, id) {
39
+ if (node.parent)
40
+ throw new Error(`building colliders: node ${node.id} has a parent; instanced buildings are expected to be root nodes`);
41
+ const { position: t, rotation: q, scale: s } = node.transform;
42
+ const size = [0, 1, 2].map((axis) => bounds.max[axis] - bounds.min[axis]);
43
+ const centre = [0, 1, 2].map((axis) => (bounds.max[axis] + bounds.min[axis]) / 2);
44
+ const scaledCentre = centre.map((value, axis) => value * s[axis]);
45
+ const offset = rotate(q, scaledCentre);
46
+ const position = [t[0] + offset[0], t[1] + offset[1], t[2] + offset[2]];
47
+ const scale = [Math.abs(size[0] * s[0]), Math.abs(size[1] * s[1]), Math.abs(size[2] * s[2])];
48
+ // World AABB from the eight corners.
49
+ const min = [Infinity, Infinity, Infinity];
50
+ const max = [-Infinity, -Infinity, -Infinity];
51
+ for (const sx of [-0.5, 0.5])
52
+ for (const sy of [-0.5, 0.5])
53
+ for (const sz of [-0.5, 0.5]) {
54
+ const corner = rotate(q, [sx * scale[0], sy * scale[1], sz * scale[2]]);
55
+ for (let axis = 0; axis < 3; axis += 1) {
56
+ const v = position[axis] + corner[axis];
57
+ if (v < min[axis])
58
+ min[axis] = v;
59
+ if (v > max[axis])
60
+ max[axis] = v;
61
+ }
62
+ }
63
+ return {
64
+ id, source: node.id,
65
+ position: position.map((v) => round(v, 3)),
66
+ rotation: [round(q[0], 6), round(q[1], 6), round(q[2], 6), round(q[3], 6)],
67
+ scale: scale.map((v) => round(v, 3)),
68
+ min, max,
69
+ };
70
+ }
71
+ /** Median-split the boxes on the longer horizontal side until each block holds at most `perBlock`. */
72
+ function splitBlocks(boxes, perBlock) {
73
+ const blocks = [];
74
+ const split = (group) => {
75
+ if (group.length <= perBlock) {
76
+ blocks.push(group);
77
+ return;
78
+ }
79
+ let lox = Infinity, hix = -Infinity, loz = Infinity, hiz = -Infinity;
80
+ for (const box of group) {
81
+ lox = Math.min(lox, box.position[0]);
82
+ hix = Math.max(hix, box.position[0]);
83
+ loz = Math.min(loz, box.position[2]);
84
+ hiz = Math.max(hiz, box.position[2]);
85
+ }
86
+ const axis = hix - lox >= hiz - loz ? 0 : 2;
87
+ const sorted = [...group].sort((a, b) => a.position[axis] - b.position[axis] || (a.id < b.id ? -1 : 1));
88
+ const half = sorted.length >> 1;
89
+ split(sorted.slice(0, half));
90
+ split(sorted.slice(half));
91
+ };
92
+ if (boxes.length)
93
+ split([...boxes]);
94
+ return blocks;
95
+ }
96
+ function planBuildingBoxes(parts, options) {
97
+ const boxes = [];
98
+ let instances = 0, skippedSmall = 0, skippedNoBounds = 0;
99
+ parts.forEach(({ part, bounds }, partIndex) => {
100
+ for (const node of part.nodes) {
101
+ if (!node.resource || !node.components?.some((component) => component.type === 'render.mesh'))
102
+ continue;
103
+ if (options.skipResource?.(node.resource))
104
+ continue;
105
+ instances += 1;
106
+ const local = bounds.get(node.resource);
107
+ if (!local) {
108
+ skippedNoBounds += 1;
109
+ continue;
110
+ }
111
+ const box = boxOfNode(node, local, `p${partIndex}.${node.id.replace(/^node\./, '')}`);
112
+ const footprint = box.scale[0] * box.scale[2];
113
+ if (footprint < options.minFootprintM2 || box.scale[1] < options.minHeightM) {
114
+ skippedSmall += 1;
115
+ continue;
116
+ }
117
+ boxes.push(box);
118
+ }
119
+ });
120
+ return { boxes, stats: { instances, boxes: boxes.length, skippedSmall, skippedNoBounds } };
121
+ }
122
+ const IDENTITY = { position: [0, 0, 0], rotation: [0, 0, 0, 1], scale: [1, 1, 1] };
123
+ function buildColliderScene(boxes, options) {
124
+ const perBlock = Math.max(options.buildingsPerBlock, Math.ceil(boxes.length / options.maxSets));
125
+ const blocks = splitBlocks(boxes, perBlock);
126
+ const nodes = [];
127
+ const groups = [];
128
+ const sets = [];
129
+ let lo = [Infinity, Infinity, Infinity];
130
+ let hi = [-Infinity, -Infinity, -Infinity];
131
+ blocks.forEach((block, index) => {
132
+ const bmin = [Infinity, Infinity, Infinity];
133
+ const bmax = [-Infinity, -Infinity, -Infinity];
134
+ for (const box of block)
135
+ for (let axis = 0; axis < 3; axis += 1) {
136
+ bmin[axis] = Math.min(bmin[axis], box.min[axis]);
137
+ bmax[axis] = Math.max(bmax[axis], box.max[axis]);
138
+ }
139
+ lo = lo.map((v, axis) => Math.min(v, bmin[axis]));
140
+ hi = hi.map((v, axis) => Math.max(v, bmax[axis]));
141
+ const node = `bc.n.${index}`, group = `bc.g.${index}`, set = `bc.s.${index}`;
142
+ nodes.push({ id: node, transform: { ...IDENTITY }, streamGroup: group, components: [{ type: 'collision.proxy-set', set }] });
143
+ groups.push({
144
+ id: group, mode: 'distance', priority: 50, dependencies: [], estimatedMemoryMiB: 1,
145
+ cells: [{ id: `bc.c.${index}`, bounds: { min: bmin.map((v) => round(v, 2)), max: bmax.map((v) => round(v, 2)) }, nodes: [node] }],
146
+ });
147
+ sets.push({
148
+ id: set, node,
149
+ static: block.map((box) => ({
150
+ id: `bc.${box.id}`, shape: 'convex', resource: exports.UNIT_BOX_RESOURCE_ID,
151
+ transform: { position: box.position, rotation: box.rotation, scale: box.scale },
152
+ })),
153
+ });
154
+ });
155
+ if (!blocks.length)
156
+ throw new Error('building colliders: no instance produced a box');
157
+ const pad = options.streamRadiusM;
158
+ const scene = {
159
+ format: 'helix.scene', version: 2, id: exports.COLLIDER_CHILD_ID, revision: '0'.repeat(16), integrity: { sha256: '0'.repeat(64) },
160
+ title: options.title ?? 'City building colliders',
161
+ units: 'meters', coordinateSystem: { handedness: 'right', up: '+Y', forward: '-Z' },
162
+ profiles: {
163
+ world: {
164
+ scene: 'scene.root', kind: 'world', persistence: 'session', maxPlayers: 32, overrideAuthority: 'none',
165
+ runtimePolicy: { memoryBudgetMiB: 32, streamRadiusM: options.streamRadiusM, allowSurfaceOverrides: false, allowItemPlacement: false },
166
+ },
167
+ },
168
+ scenes: [{ id: 'scene.root', nodes: nodes.map((node) => node.id), streamGroups: groups.map((group) => group.id) }],
169
+ resources: [{
170
+ id: exports.UNIT_BOX_RESOURCE_ID, kind: 'collider', source: { kind: 'bundle', assetId: `colliders:unit-box:${options.unitBox.sha256}`, uri: options.unitBox.uri },
171
+ integrity: { sha256: options.unitBox.sha256 }, bytes: options.unitBox.bytes, mimeType: 'model/gltf-binary', required: true,
172
+ }],
173
+ nodes, itemDefinitions: [], itemInstances: [], terrain: { kind: 'none' },
174
+ environment: { background: false, intensityScale: 1, rotationYDeg: 0, exposureEV100: 0, fallbackColor: '#20242b', required: false },
175
+ lights: [],
176
+ spawns: [{ id: 'spawn.main', position: [round((lo[0] + hi[0]) / 2, 2), round(hi[1] + 1, 2), round((lo[2] + hi[2]) / 2, 2)], rotation: [0, 0, 0, 1], profileAccess: ['world'], clearanceRadiusM: 0.45, clearanceHeightM: 1.9 }],
177
+ collision: { sets },
178
+ navigation: { walkableSurfaces: [], agent: { radiusM: 0.35, heightM: 1.8, stepHeightM: 0.32, maxSlopeDeg: 48 }, navmesh: null, fallback: 'physics-walkability' },
179
+ placement: { bounds: { min: lo.map((v) => round(v - pad, 1)), max: hi.map((v) => round(v + pad, 1)) }, maxItemInstances: 0, snapGridM: 0.05, allowedProfiles: ['world'] },
180
+ surfaces: [], materials: [], behaviors: [], streamGroups: groups,
181
+ capabilities: { required: ['helix.scene-collision/1'], optional: [] }, runtimeExtensions: [], adapters: options.adapters,
182
+ };
183
+ return { scene, stats: { instances: boxes.length, boxes: boxes.length, skippedSmall: 0, skippedNoBounds: 0, sets: sets.length, maxPerSet: Math.max(...blocks.map((block) => block.length)) } };
184
+ }
185
+ /** The sealing order every Scene v2 builder uses: revision = first 16 hex of the digest with revision and integrity zeroed. */
186
+ function sealScene(scene) {
187
+ scene.revision = '0'.repeat(16);
188
+ scene.integrity = { sha256: '0'.repeat(64) };
189
+ const digest = (0, helix_manifest_1.computeSceneDocumentIntegrity)(scene);
190
+ scene.revision = digest.slice(0, 16);
191
+ scene.integrity = { sha256: (0, helix_manifest_1.computeSceneDocumentIntegrity)(scene) };
192
+ return scene;
193
+ }
194
+ /**
195
+ * Mounts the collider child in a root document: the mount definition, the node that places it in the root's eager city group
196
+ * (so it is resident whenever the city is), and the group's declared memory. Returns a new, resealed root.
197
+ */
198
+ function mountColliderChild(root, child, budgetMiB = 32) {
199
+ const next = structuredClone(root);
200
+ const mountId = 'mount.city.colliders', nodeId = 'node.city.colliders';
201
+ if (next.mounts?.some((mount) => mount.id === mountId))
202
+ throw new Error('the root already mounts the city colliders');
203
+ const group = next.streamGroups.find((candidate) => next.nodes.some((node) => node.streamGroup === candidate.id && node.components?.some((c) => c.type === 'scene.mount')));
204
+ if (!group)
205
+ throw new Error('the root has no stream group that places mounts');
206
+ const mount = { id: mountId, scene: { id: child.id, revision: child.revision }, integrity: { sha256: child.integrity.sha256 }, profile: 'world', budgetMiB, depth: 0 };
207
+ next.mounts = [...(next.mounts ?? []), mount];
208
+ next.nodes.push({ id: nodeId, streamGroup: group.id, transform: { ...IDENTITY }, components: [{ type: 'scene.mount', mount: mountId }] });
209
+ group.cells[0].nodes.push(nodeId);
210
+ group.estimatedMemoryMiB += budgetMiB;
211
+ next.scenes[0].nodes.push(nodeId);
212
+ return sealScene(next);
213
+ }
214
+ //# sourceMappingURL=buildingBoxes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildingBoxes.js","sourceRoot":"","sources":["../../../src/city/colliders/buildingBoxes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerCityColliders(city: Command, fail: (message: string) => never): void;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ // `helix city colliders apply`.
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.registerCityColliders = registerCityColliders;
5
+ const node_path_1 = require("node:path");
6
+ const apply_1 = require("./apply");
7
+ function registerCityColliders(city, fail) {
8
+ const colliders = city
9
+ .command('colliders')
10
+ .description('Complete the collision of a published city Scene: collider cells for elevated decks, ramps and rails, and a collider-only child Scene of building boxes');
11
+ colliders
12
+ .command('apply')
13
+ .description('Read a published city root from a data prefix (https origin or folder) and write the new objects (resealed root, deck-collider cells, building-box child Scene) to --out')
14
+ .requiredOption('--source <prefix>', 'data prefix holding scene/<root>/ (https origin or folder)')
15
+ .requiredOption('--root <name>', 'the root Scene folder under scene/ to complete')
16
+ .requiredOption('--new-root <name>', 'the folder name the completed root is written as')
17
+ .requiredOption('--out <dir>', 'output folder (mirrors the prefix layout)')
18
+ .option('--road-cell <m>', 'road render/collider cell size in metres', '1024')
19
+ .option('--no-decks', 'skip the elevated-deck collider cells')
20
+ .option('--no-buildings', 'skip the building-box child Scene')
21
+ .option('--stream-radius <m>', 'physics radius of the building colliders in metres', '120')
22
+ .option('--per-block <n>', 'buildings per collider set', '60')
23
+ .option('--json', 'print the report as JSON')
24
+ .action(async (opts) => {
25
+ try {
26
+ const roadCellM = Number(opts.roadCell);
27
+ const streamRadiusM = Number(opts.streamRadius);
28
+ const buildingsPerBlock = Number(opts.perBlock);
29
+ if (!(roadCellM > 0) || !(streamRadiusM > 0) || !(Number.isInteger(buildingsPerBlock) && buildingsPerBlock >= 1))
30
+ fail('✖ --road-cell, --stream-radius and --per-block must be positive numbers');
31
+ const source = /^https?:\/\//.test(opts.source) ? opts.source : (0, node_path_1.resolve)(opts.source);
32
+ const result = await (0, apply_1.applyColliders)({
33
+ source: (0, apply_1.prefixSource)(source), rootName: opts.root, newRootName: opts.newRoot,
34
+ buildings: { enabled: opts.buildings, streamRadiusM, buildingsPerBlock },
35
+ decks: { enabled: opts.decks, roadCellM },
36
+ log: (message) => console.error(message),
37
+ });
38
+ await (0, apply_1.writeFiles)((0, node_path_1.resolve)(opts.out), result.files);
39
+ console.log(opts.json ? JSON.stringify(result.report, null, 2) : `✔ ${result.files.length} files written to ${opts.out}\n${JSON.stringify(result.report, null, 2)}`);
40
+ }
41
+ catch (err) {
42
+ fail(`✖ ${err instanceof Error ? err.message : String(err)}`);
43
+ }
44
+ });
45
+ }
46
+ //# sourceMappingURL=command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.js","sourceRoot":"","sources":["../../../src/city/colliders/command.ts"],"names":[],"mappings":"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"}