@buley/hexgrid-3d 3.4.0 → 3.5.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.
@@ -1 +1 @@
1
- {"version":3,"file":"DashAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/DashAdapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAAM;gBAEN,YAAY,EAAE,GAAG;IAI7B;;;;;OAKG;IACH,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG;CA6BtD"}
1
+ {"version":3,"file":"DashAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/DashAdapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAAM;gBAEN,YAAY,EAAE,GAAG;IAI7B;;;;;OAKG;IACH,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG;CA6BtD"}
@@ -4,6 +4,7 @@
4
4
  * This adapter subscribes to a Dash "LiveQuery" which returns pointers to shared memory (SharedArrayBuffer)
5
5
  * or Float32Arrays. It then syncs this data directly to the HexGridWasm instance.
6
6
  */
7
+ import { logger } from '../lib/logger';
7
8
  export class DashAdapter {
8
9
  constructor(dashInstance) {
9
10
  this.dash = dashInstance;
@@ -15,11 +16,11 @@ export class DashAdapter {
15
16
  * @param gridInstance The WASM instance of the HexGrid
16
17
  */
17
18
  bindSemanticSearch(query, particleSystem) {
18
- console.log('[DashAdapter] Binding semantic search:', query);
19
+ logger.log('[DashAdapter] Binding semantic search:', query);
19
20
  // Hypothetical Zero-Copy API from Dash 2.0
20
21
  if (this.dash.liveQueryPtr) {
21
22
  this.dash.liveQueryPtr(`SELECT embedding FROM dash_vec_idx WHERE embedding MATCH '${query}'`).subscribe((handle) => {
22
- console.log(`[DashAdapter] Received ${handle.size} bytes from Dash.`);
23
+ logger.log(`[DashAdapter] Received ${handle.size} bytes from Dash.`);
23
24
  // Assume the handle.buffer contains [pos, color, scale] interleaved or tightly packed
24
25
  // For this MVP, we treat it as just positions
25
26
  const floatView = new Float32Array(handle.buffer);
@@ -36,7 +37,7 @@ export class DashAdapter {
36
37
  });
37
38
  }
38
39
  else {
39
- console.warn('[DashAdapter] Dash instance does not support Zero-Copy liveQueryPtr yet.');
40
+ logger.warn('[DashAdapter] Dash instance does not support Zero-Copy liveQueryPtr yet.');
40
41
  }
41
42
  }
42
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FluidEngineFactory.d.ts","sourceRoot":"","sources":["../../src/algorithms/FluidEngineFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,MAAM,WAAW,GAAG,cAAc,GAAG,oBAAoB,GAAG,oBAAoB,CAAC;AAEvF;;;;;;GAMG;AACH,qBAAa,kBAAkB;WAChB,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC;CA6BjE"}
1
+ {"version":3,"file":"FluidEngineFactory.d.ts","sourceRoot":"","sources":["../../src/algorithms/FluidEngineFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAG9D,MAAM,MAAM,WAAW,GAAG,cAAc,GAAG,oBAAoB,GAAG,oBAAoB,CAAC;AAEvF;;;;;;GAMG;AACH,qBAAa,kBAAkB;WAChB,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC;CA6BjE"}
@@ -1,6 +1,7 @@
1
1
  import { StableFluids3D } from './FluidSimulation3D';
2
2
  import { FluidSimulationWebNN } from './FluidSimulationWebNN';
3
3
  import { FluidSimulation3DGPU } from './FluidSimulation3DGPU';
4
+ import { logger } from '../lib/logger';
4
5
  /**
5
6
  * Factory to select the best available Fluid Engine.
6
7
  * Priority:
@@ -15,27 +16,27 @@ export class FluidEngineFactory {
15
16
  const webnn = new FluidSimulationWebNN(config);
16
17
  const webnnSupported = await webnn.initialize();
17
18
  if (webnnSupported) {
18
- console.log("Fluid Engine: Using WebNN (NPU)");
19
+ logger.log("Fluid Engine: Using WebNN (NPU)");
19
20
  return webnn;
20
21
  }
21
22
  }
22
23
  catch (e) {
23
- console.warn("Fluid Engine: WebNN init failed", e);
24
+ logger.warn("Fluid Engine: WebNN init failed", e);
24
25
  }
25
26
  // 2. Try WebGPU
26
27
  try {
27
28
  const webgpu = new FluidSimulation3DGPU(config);
28
29
  const webgpuSupported = await webgpu.initialize();
29
30
  if (webgpuSupported) {
30
- console.log("Fluid Engine: Using WebGPU");
31
+ logger.log("Fluid Engine: Using WebGPU");
31
32
  return webgpu;
32
33
  }
33
34
  }
34
35
  catch (e) {
35
- console.warn("Fluid Engine: WebGPU init failed", e);
36
+ logger.warn("Fluid Engine: WebGPU init failed", e);
36
37
  }
37
38
  // 3. Fallback to CPU
38
- console.log("Fluid Engine: using CPU Fallback");
39
+ logger.log("Fluid Engine: using CPU Fallback");
39
40
  return new StableFluids3D(config);
40
41
  }
41
42
  }
@@ -1 +1 @@
1
- {"version":3,"file":"HexGrid.d.ts","sourceRoot":"","sources":["../../src/components/HexGrid.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAA;AAYhF,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AAI/C,YAAY,EAAE,KAAK,EAAE,CAAA;AAWrB,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO;IAEvC,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAA;IACrB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAA;IAGhB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IACzC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAEnC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAA;IAC9C,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,KAAK,IAAI,CAAA;IAC5G,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,0BAA0B,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACpD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,KAAK,CAAA;IACZ,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAC1C,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAoLD,eAAO,MAAM,OAAO,GAAI,CAAC,GAAG,OAAO,EAAE,iMAalC,YAAY,CAAC,CAAC,CAAC,4CAytIjB,CAAA;AAk7DD,eAAe,OAAO,CAAC"}
1
+ {"version":3,"file":"HexGrid.d.ts","sourceRoot":"","sources":["../../src/components/HexGrid.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAA;AAYhF,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AAI/C,YAAY,EAAE,KAAK,EAAE,CAAA;AAWrB,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO;IAEvC,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAA;IACrB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAA;IAGhB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IACzC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAEnC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAA;IAC9C,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,KAAK,IAAI,CAAA;IAC5G,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,0BAA0B,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACpD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,KAAK,CAAA;IACZ,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAC1C,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAoLD,eAAO,MAAM,OAAO,GAAI,CAAC,GAAG,OAAO,EAAE,iMAalC,YAAY,CAAC,CAAC,CAAC,4CAwtIjB,CAAA;AAk7DD,eAAe,OAAO,CAAC"}
@@ -283,10 +283,9 @@ export const HexGrid = ({ items, photos: photosProp, onItemClick, onHexClick, sp
283
283
  // gridScale >1 reduces effective hex radius (more hexes), <1 increases radius (fewer hexes)
284
284
  gridScale: 1,
285
285
  // tileSize: base hex radius in pixels (editable)
286
- // Increased from 6 to 12 for better performance (larger hexes = fewer total hexes = better performance)
287
- tileSize: 12,
286
+ tileSize: 8,
288
287
  // hexSpacing: multiplier for hex size (1.0 = perfect touching, <1.0 = gaps, >1.0 = overlap)
289
- hexSpacing: 1.0,
288
+ hexSpacing: 0.95,
290
289
  // sphericalDensity: multiplier for spherical grid density (1.0 = default, >1.0 = more hexes)
291
290
  sphericalDensity: 1.4,
292
291
  // curvature controls (degrees) - start with a visually pleasing curvature
@@ -304,8 +303,8 @@ export const HexGrid = ({ items, photos: photosProp, onItemClick, onHexClick, sp
304
303
  polePower: 0.9,
305
304
  // Render both sides option: when true, draw an antipodal copy so images show on inside/outside
306
305
  renderBothSides: false,
307
- // Worker debug logs (ENABLED for debugging evolution issues)
308
- debugLogs: true,
306
+ // Worker debug logs (disabled by default for performance)
307
+ debugLogs: false,
309
308
  // Cluster tiling defaults: preserve aspect, center anchor, no global alignment,
310
309
  // zero uv inset for perfect alignment (seam blending handled separately), no jitter by default
311
310
  clusterPreserveAspect: true,
@@ -1,13 +1,7 @@
1
1
  export declare const logger: {
2
2
  debug: (..._args: unknown[]) => void;
3
- log: {
4
- (...data: any[]): void;
5
- (...data: any[]): void;
6
- };
7
- info: {
8
- (...data: any[]): void;
9
- (...data: any[]): void;
10
- };
3
+ log: (..._args: unknown[]) => void;
4
+ info: (..._args: unknown[]) => void;
11
5
  warn: {
12
6
  (...data: any[]): void;
13
7
  (...data: any[]): void;
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,MAAM;sBANK,OAAO,EAAE;;;;;;;;;;;;;;;;;CAYhC,CAAA"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,MAAM;sBANK,OAAO,EAAE;oBAAT,OAAO,EAAE;qBAAT,OAAO,EAAE;;;;;;;;;CAYhC,CAAA"}
@@ -2,8 +2,8 @@ const noop = (..._args) => { };
2
2
  const isDev = typeof process !== 'undefined' && process?.env?.NODE_ENV !== 'production';
3
3
  export const logger = {
4
4
  debug: isDev ? console.debug.bind(console) : noop,
5
- log: console.log.bind(console),
6
- info: console.info.bind(console),
5
+ log: isDev ? console.log.bind(console) : noop,
6
+ info: isDev ? console.info.bind(console) : noop,
7
7
  warn: console.warn.bind(console),
8
8
  error: console.error.bind(console),
9
9
  };
@@ -1 +1 @@
1
- {"version":3,"file":"HexGridWasmWrapper.d.ts","sourceRoot":"","sources":["../../src/wasm/HexGridWasmWrapper.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"HexGridWasmWrapper.d.ts","sourceRoot":"","sources":["../../src/wasm/HexGridWasmWrapper.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * @module wasm/HexGridWasmWrapper
8
8
  */
9
+ import { logger } from '../lib/logger';
9
10
  /**
10
11
  * Wrapper class that provides TypeScript interface to WASM
11
12
  * with automatic fallback
@@ -36,11 +37,11 @@ export class HexGridWasmWrapper {
36
37
  const wasmModule = await import('../rust/pkg/hexgrid_wasm');
37
38
  await wasmModule.default();
38
39
  this.module = wasmModule;
39
- console.log('[HexGrid] WASM module loaded successfully');
40
+ logger.log('[HexGrid] WASM module loaded successfully');
40
41
  return this.module;
41
42
  }
42
43
  catch (error) {
43
- console.warn('[HexGrid] WASM module not available, using fallback:', error);
44
+ logger.warn('[HexGrid] WASM module not available, using fallback:', error);
44
45
  this.loadFailed = true;
45
46
  return null;
46
47
  }
@@ -1 +1 @@
1
- {"version":3,"file":"WebGPUContext.d.ts","sourceRoot":"","sources":["../../src/webgpu/WebGPUContext.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAgB;IACvC,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,WAAW,CAAkB;IAErC,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,aAAa;IAOnC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAoCpC,SAAS,IAAI,SAAS,GAAG,IAAI;IAI7B,UAAU,IAAI,UAAU,GAAG,IAAI;IAI/B,WAAW,IAAI,OAAO;CAGvB"}
1
+ {"version":3,"file":"WebGPUContext.d.ts","sourceRoot":"","sources":["../../src/webgpu/WebGPUContext.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAgB;IACvC,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,WAAW,CAAkB;IAErC,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,aAAa;IAOnC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAoCpC,SAAS,IAAI,SAAS,GAAG,IAAI;IAI7B,UAAU,IAAI,UAAU,GAAG,IAAI;IAI/B,WAAW,IAAI,OAAO;CAGvB"}
@@ -2,6 +2,7 @@
2
2
  * WebGPU Context Manager
3
3
  * Handles the creation and management of the WebGPU Device and Adapter.
4
4
  */
5
+ import { logger } from '../lib/logger';
5
6
  export class WebGPUContext {
6
7
  constructor() {
7
8
  this.adapter = null;
@@ -19,7 +20,7 @@ export class WebGPUContext {
19
20
  */
20
21
  async initialize() {
21
22
  if (typeof navigator === 'undefined' || !navigator.gpu) {
22
- console.warn('WebGPU is not supported in this environment.');
23
+ logger.warn('WebGPU is not supported in this environment.');
23
24
  this.isSupported = false;
24
25
  return false;
25
26
  }
@@ -28,22 +29,22 @@ export class WebGPUContext {
28
29
  powerPreference: 'high-performance'
29
30
  });
30
31
  if (!this.adapter) {
31
- console.warn('No WebGPU adapter found.');
32
+ logger.warn('No WebGPU adapter found.');
32
33
  this.isSupported = false;
33
34
  return false;
34
35
  }
35
36
  this.device = await this.adapter.requestDevice();
36
37
  this.device.lost.then((info) => {
37
- console.error(`WebGPU device lost: ${info.message}`);
38
+ logger.error(`WebGPU device lost: ${info.message}`);
38
39
  this.device = null;
39
40
  this.isSupported = false;
40
41
  });
41
42
  this.isSupported = true;
42
- console.log('WebGPU initialized successfully.');
43
+ logger.log('WebGPU initialized successfully.');
43
44
  return true;
44
45
  }
45
46
  catch (e) {
46
- console.error('Failed to initialize WebGPU:', e);
47
+ logger.error('Failed to initialize WebGPU:', e);
47
48
  this.isSupported = false;
48
49
  return false;
49
50
  }
@@ -1 +1 @@
1
- {"version":3,"file":"WebNNContext.d.ts","sourceRoot":"","sources":["../../src/webnn/WebNNContext.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAEpD,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAe;IACtC,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,WAAW,CAAkB;IAErC,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,YAAY;IAOlC;;OAEG;IACG,UAAU,CAAC,UAAU,GAAE,eAAuB,GAAG,OAAO,CAAC,OAAO,CAAC;IAuCvE,UAAU,IAAI,SAAS,GAAG,IAAI;IAI9B,aAAa,IAAI,eAAe;IAIhC,WAAW,IAAI,OAAO;CAGvB;AAGD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,SAAS;QACjB,EAAE,EAAE;YACF,aAAa,CAAC,OAAO,CAAC,EAAE;gBAAE,UAAU,CAAC,EAAE,MAAM,CAAA;aAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;SACtE,CAAC;KACH;IAED,UAAU,SAAS;QAEjB,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;KACtI;IAED,UAAU,OAAO;KAEhB;IAED,UAAU,eAAe;KAExB;CACF"}
1
+ {"version":3,"file":"WebNNContext.d.ts","sourceRoot":"","sources":["../../src/webnn/WebNNContext.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAEpD,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAe;IACtC,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,WAAW,CAAkB;IAErC,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,YAAY;IAOlC;;OAEG;IACG,UAAU,CAAC,UAAU,GAAE,eAAuB,GAAG,OAAO,CAAC,OAAO,CAAC;IAuCvE,UAAU,IAAI,SAAS,GAAG,IAAI;IAI9B,aAAa,IAAI,eAAe;IAIhC,WAAW,IAAI,OAAO;CAGvB;AAGD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,SAAS;QACjB,EAAE,EAAE;YACF,aAAa,CAAC,OAAO,CAAC,EAAE;gBAAE,UAAU,CAAC,EAAE,MAAM,CAAA;aAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;SACtE,CAAC;KACH;IAED,UAAU,SAAS;QAEjB,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;KACtI;IAED,UAAU,OAAO;KAEhB;IAED,UAAU,eAAe;KAExB;CACF"}
@@ -3,6 +3,7 @@
3
3
  * Handles the creation and management of the WebNN MLContext.
4
4
  * Prioritizes NPU -> GPU -> CPU.
5
5
  */
6
+ import { logger } from '../lib/logger';
6
7
  export class WebNNContext {
7
8
  constructor() {
8
9
  this.context = null;
@@ -20,7 +21,7 @@ export class WebNNContext {
20
21
  */
21
22
  async initialize(preference = 'npu') {
22
23
  if (typeof navigator === 'undefined' || !navigator.ml) {
23
- console.warn('WebNN is not supported in this environment.');
24
+ logger.warn('WebNN is not supported in this environment.');
24
25
  this.isSupported = false;
25
26
  return false;
26
27
  }
@@ -29,11 +30,11 @@ export class WebNNContext {
29
30
  this.context = await navigator.ml.createContext({ deviceType: preference });
30
31
  this.deviceType = preference;
31
32
  this.isSupported = true;
32
- console.log(`WebNN initialized successfully on ${preference}`);
33
+ logger.log(`WebNN initialized successfully on ${preference}`);
33
34
  return true;
34
35
  }
35
36
  catch (e) {
36
- console.warn(`Failed to initialize WebNN on ${preference}, trying fallback chain...`, e);
37
+ logger.warn(`Failed to initialize WebNN on ${preference}, trying fallback chain...`, e);
37
38
  // Fallback chain: NPU -> GPU -> CPU
38
39
  const chain = ['npu', 'gpu', 'cpu'];
39
40
  const startIndex = chain.indexOf(preference) + 1;
@@ -43,11 +44,11 @@ export class WebNNContext {
43
44
  this.context = await navigator.ml.createContext({ deviceType: fallback });
44
45
  this.deviceType = fallback;
45
46
  this.isSupported = true;
46
- console.log(`WebNN initialized successfully on fallback ${fallback}`);
47
+ logger.log(`WebNN initialized successfully on fallback ${fallback}`);
47
48
  return true;
48
49
  }
49
50
  catch (err) {
50
- console.warn(`Failed to initialize WebNN on fallback ${fallback}`, err);
51
+ logger.warn(`Failed to initialize WebNN on fallback ${fallback}`, err);
51
52
  }
52
53
  }
53
54
  }
@@ -7,7 +7,11 @@
7
7
  // - defensive guards and error reporting via postMessage({type:'error', ...})
8
8
  import { getGridBounds as _getGridBounds, distanceBetween as _distanceBetween, calculateUvBoundsFromGridPosition as _calculateUvBoundsFromGridPosition, calculateContiguity as _calculateContiguity, calculatePhotoContiguity as _calculatePhotoContiguity, } from './hexgrid-math';
9
9
  const WORKER_ID = Math.random().toString(36).substring(7);
10
- console.log('[hexgrid-worker] loaded id=', WORKER_ID);
10
+ /** Guarded log only emits when workerDebug.debugLogs is true. */
11
+ function debugLog(...args) {
12
+ if (workerDebug.debugLogs)
13
+ console.log(...args);
14
+ }
11
15
  const workerDebug = {
12
16
  cohesionBoost: 6.0, // BOOSTED: strongly favor growth near cluster centroids to build larger regions
13
17
  enableMerges: true, // ENABLED: merge small fragments into nearby larger clusters
@@ -152,7 +156,7 @@ function calculateUvBoundsFromGridPosition(gridCol, gridRow, tilesX, tilesY) {
152
156
  function findConnectedComponents(indices, positions, hexRadius) {
153
157
  // Immediate synchronous check - if this doesn't log, the function isn't being called or is blocked
154
158
  const startMarker = performance.now();
155
- console.log('[findConnectedComponents] FUNCTION ENTERED - indices.length=', indices.length, 'positions.length=', positions.length, 'hexRadius=', hexRadius, 'marker=', startMarker);
159
+ debugLog('[findConnectedComponents] FUNCTION ENTERED - indices.length=', indices.length, 'positions.length=', positions.length, 'hexRadius=', hexRadius, 'marker=', startMarker);
156
160
  // Validate inputs immediately
157
161
  if (!indices || !Array.isArray(indices)) {
158
162
  console.error('[findConnectedComponents] Invalid indices:', indices);
@@ -166,13 +170,13 @@ function findConnectedComponents(indices, positions, hexRadius) {
166
170
  console.error('[findConnectedComponents] Invalid hexRadius:', hexRadius);
167
171
  return [];
168
172
  }
169
- console.log('[findConnectedComponents] About to enter try block');
173
+ debugLog('[findConnectedComponents] About to enter try block');
170
174
  // Add immediate log after try block entry to confirm execution reaches here
171
175
  let tryBlockEntered = false;
172
176
  try {
173
177
  tryBlockEntered = true;
174
- console.log('[findConnectedComponents] ✅ TRY BLOCK ENTERED - marker=', performance.now() - startMarker, 'ms');
175
- console.log('[findConnectedComponents] Inside try block - Starting with', indices.length, 'indices');
178
+ debugLog('[findConnectedComponents] ✅ TRY BLOCK ENTERED - marker=', performance.now() - startMarker, 'ms');
179
+ debugLog('[findConnectedComponents] Inside try block - Starting with', indices.length, 'indices');
176
180
  const set = new Set(indices);
177
181
  const visited = new Set();
178
182
  const comps = [];
@@ -181,7 +185,7 @@ function findConnectedComponents(indices, positions, hexRadius) {
181
185
  if (visited.has(start))
182
186
  continue;
183
187
  componentCount++;
184
- console.log('[findConnectedComponents] Starting component', componentCount, 'from index', start);
188
+ debugLog('[findConnectedComponents] Starting component', componentCount, 'from index', start);
185
189
  const q = [start];
186
190
  visited.add(start);
187
191
  const comp = [];
@@ -194,7 +198,7 @@ function findConnectedComponents(indices, positions, hexRadius) {
194
198
  break;
195
199
  }
196
200
  if (iterations % 100 === 0) {
197
- console.log('[findConnectedComponents] Component', componentCount, 'iteration', iterations, 'queue length', q.length);
201
+ debugLog('[findConnectedComponents] Component', componentCount, 'iteration', iterations, 'queue length', q.length);
198
202
  }
199
203
  const cur = q.shift();
200
204
  if (cur === undefined || cur === null) {
@@ -224,12 +228,12 @@ function findConnectedComponents(indices, positions, hexRadius) {
224
228
  continue;
225
229
  }
226
230
  }
227
- console.log('[findConnectedComponents] Component', componentCount, 'complete:', comp.length, 'nodes,', iterations, 'iterations');
231
+ debugLog('[findConnectedComponents] Component', componentCount, 'complete:', comp.length, 'nodes,', iterations, 'iterations');
228
232
  comps.push(comp);
229
233
  }
230
- console.log('[findConnectedComponents] Complete:', comps.length, 'components found');
234
+ debugLog('[findConnectedComponents] Complete:', comps.length, 'components found');
231
235
  const elapsed = performance.now() - startMarker;
232
- console.log('[findConnectedComponents] ✅ RETURNING - elapsed=', elapsed, 'ms, components=', comps.length);
236
+ debugLog('[findConnectedComponents] ✅ RETURNING - elapsed=', elapsed, 'ms, components=', comps.length);
233
237
  return comps;
234
238
  }
235
239
  catch (e) {
@@ -250,7 +254,7 @@ function findConnectedComponents(indices, positions, hexRadius) {
250
254
  }
251
255
  function calculatePhotoCentroids(infections, positions, hexRadius) {
252
256
  try {
253
- console.log('[calculatePhotoCentroids] Starting with', infections.size, 'infections');
257
+ debugLog('[calculatePhotoCentroids] Starting with', infections.size, 'infections');
254
258
  const byPhoto = new Map();
255
259
  for (const [idx, inf] of infections) {
256
260
  if (!inf || !inf.photo)
@@ -259,14 +263,14 @@ function calculatePhotoCentroids(infections, positions, hexRadius) {
259
263
  arr.push(idx);
260
264
  byPhoto.set(inf.photo.id, arr);
261
265
  }
262
- console.log('[calculatePhotoCentroids] Grouped into', byPhoto.size, 'photos');
266
+ debugLog('[calculatePhotoCentroids] Grouped into', byPhoto.size, 'photos');
263
267
  const centroids = new Map();
264
268
  let photoNum = 0;
265
269
  for (const [photoId, inds] of byPhoto) {
266
270
  photoNum++;
267
- console.log('[calculatePhotoCentroids] Processing photo', photoNum, '/', byPhoto.size, 'photoId=', photoId, 'indices=', inds.length);
271
+ debugLog('[calculatePhotoCentroids] Processing photo', photoNum, '/', byPhoto.size, 'photoId=', photoId, 'indices=', inds.length);
268
272
  try {
269
- console.log('[calculatePhotoCentroids] About to call findConnectedComponents with', inds.length, 'indices');
273
+ debugLog('[calculatePhotoCentroids] About to call findConnectedComponents with', inds.length, 'indices');
270
274
  const callStartTime = performance.now();
271
275
  let comps;
272
276
  try {
@@ -282,7 +286,7 @@ function calculatePhotoCentroids(infections, positions, hexRadius) {
282
286
  else {
283
287
  comps = findConnectedComponents(inds, positions, hexRadius);
284
288
  const callElapsed = performance.now() - callStartTime;
285
- console.log('[calculatePhotoCentroids] findConnectedComponents RETURNED with', comps.length, 'components after', callElapsed, 'ms');
289
+ debugLog('[calculatePhotoCentroids] findConnectedComponents RETURNED with', comps.length, 'components after', callElapsed, 'ms');
286
290
  }
287
291
  }
288
292
  catch (e) {
@@ -291,8 +295,8 @@ function calculatePhotoCentroids(infections, positions, hexRadius) {
291
295
  // Return empty components on error to allow evolution to continue
292
296
  comps = [];
293
297
  }
294
- console.log('[calculatePhotoCentroids] findConnectedComponents returned', comps.length, 'components');
295
- console.log('[calculatePhotoCentroids] Found', comps.length, 'components for photo', photoId);
298
+ debugLog('[calculatePhotoCentroids] findConnectedComponents returned', comps.length, 'components');
299
+ debugLog('[calculatePhotoCentroids] Found', comps.length, 'components for photo', photoId);
296
300
  const cs = [];
297
301
  for (const comp of comps) {
298
302
  let sx = 0, sy = 0;
@@ -313,7 +317,7 @@ function calculatePhotoCentroids(infections, positions, hexRadius) {
313
317
  centroids.set(photoId, []);
314
318
  }
315
319
  }
316
- console.log('[calculatePhotoCentroids] Completed, returning', centroids.size, 'photo centroids');
320
+ debugLog('[calculatePhotoCentroids] Completed, returning', centroids.size, 'photo centroids');
317
321
  return centroids;
318
322
  }
319
323
  catch (e) {
@@ -330,7 +334,7 @@ function calculateContiguity(indices, positions, hexRadius) {
330
334
  function assignClusterGridPositions(infections, positions, hexRadius) {
331
335
  const debugCenters = [];
332
336
  try {
333
- console.log('[assignClusterGridPositions] Starting with', infections.size, 'infections');
337
+ debugLog('[assignClusterGridPositions] Starting with', infections.size, 'infections');
334
338
  // Group infections by photo
335
339
  const byPhoto = new Map();
336
340
  for (const [idx, inf] of infections) {
@@ -340,7 +344,7 @@ function assignClusterGridPositions(infections, positions, hexRadius) {
340
344
  arr.push(idx);
341
345
  byPhoto.set(inf.photo.id, arr);
342
346
  }
343
- console.log('[assignClusterGridPositions] Processing', byPhoto.size, 'unique photos');
347
+ debugLog('[assignClusterGridPositions] Processing', byPhoto.size, 'unique photos');
344
348
  // Cluster size analytics
345
349
  let totalClusters = 0;
346
350
  let clusterSizes = [];
@@ -353,7 +357,7 @@ function assignClusterGridPositions(infections, positions, hexRadius) {
353
357
  if (comp && comp.length > 0)
354
358
  clusterSizes.push(comp.length);
355
359
  }
356
- console.log('[assignClusterGridPositions] Photo', photoId.substring(0, 8), 'has', components.length, 'clusters, sizes:', components.map((c) => c.length).join(','));
360
+ debugLog('[assignClusterGridPositions] Photo', photoId.substring(0, 8), 'has', components.length, 'clusters, sizes:', components.map((c) => c.length).join(','));
357
361
  // Process each cluster separately
358
362
  let clusterIndex = 0;
359
363
  for (const cluster of components) {
@@ -432,7 +436,7 @@ function assignClusterGridPositions(infections, positions, hexRadius) {
432
436
  tilesY++;
433
437
  }
434
438
  }
435
- console.log('[assignClusterGridPositions][hex-lattice] cluster', photoId.substring(0, 8), 'size', cluster.length, 'latticeCols', latticeCols, 'latticeRows', latticeRows, 'tilesX', tilesX, 'tilesY', tilesY);
439
+ debugLog('[assignClusterGridPositions][hex-lattice] cluster', photoId.substring(0, 8), 'size', cluster.length, 'latticeCols', latticeCols, 'latticeRows', latticeRows, 'tilesX', tilesX, 'tilesY', tilesY);
436
440
  // Build optional serpentine ordering for assignment uniqueness (not strictly needed since lattice mapping is direct)
437
441
  const serpentine = workerDebug.clusterScanMode === 'serpentine';
438
442
  // Assign each infection a gridPosition derived from lattice coordinates compressed into tile grid domain.
@@ -586,7 +590,7 @@ function assignClusterGridPositions(infections, positions, hexRadius) {
586
590
  }
587
591
  const clusterWidth = Math.max(0, maxX - minX);
588
592
  const clusterHeight = Math.max(0, maxY - minY);
589
- console.log('[assignClusterGridPositions] Cluster bounds:', {
593
+ debugLog('[assignClusterGridPositions] Cluster bounds:', {
590
594
  photoId: photoId.substring(0, 8),
591
595
  clusterIndex,
592
596
  hexCount: cluster.length,
@@ -601,7 +605,7 @@ function assignClusterGridPositions(infections, positions, hexRadius) {
601
605
  // This ensures the tile grid matches the spatial layout of the cluster
602
606
  const clusterAspect = clusterHeight > 0 ? clusterWidth / clusterHeight : 1.0;
603
607
  const targetTileCount = 16; // Target ~16 tiles total for good image distribution
604
- console.log('[assignClusterGridPositions] Cluster aspect:', clusterAspect.toFixed(3), '(width/height)');
608
+ debugLog('[assignClusterGridPositions] Cluster aspect:', clusterAspect.toFixed(3), '(width/height)');
605
609
  let tilesX;
606
610
  let tilesY;
607
611
  if (cluster.length === 1) {
@@ -659,13 +663,13 @@ function assignClusterGridPositions(infections, positions, hexRadius) {
659
663
  newTilesY = Math.max(1, Math.min(16, newTilesY));
660
664
  tilesX = newTilesX;
661
665
  tilesY = newTilesY;
662
- console.log('[assignClusterGridPositions] Expanded tile grid to', tilesX, 'x', tilesY, '=', tilesX * tilesY, 'tiles');
666
+ debugLog('[assignClusterGridPositions] Expanded tile grid to', tilesX, 'x', tilesY, '=', tilesX * tilesY, 'tiles');
663
667
  }
664
668
  }
665
669
  catch (e) {
666
670
  // if anything goes wrong, keep original tilesX/tilesY
667
671
  }
668
- console.log('[assignClusterGridPositions] Final tile dimensions:', tilesX, 'x', tilesY, '=', tilesX * tilesY, 'tiles for', cluster.length, 'hexes');
672
+ debugLog('[assignClusterGridPositions] Final tile dimensions:', tilesX, 'x', tilesY, '=', tilesX * tilesY, 'tiles for', cluster.length, 'hexes');
669
673
  // Single-hex or degenerate clusters: assign a deterministic tile so single hexes don't all use [0,0]
670
674
  if (cluster.length === 1 ||
671
675
  clusterWidth < 1e-6 ||
@@ -859,7 +863,7 @@ function assignClusterGridPositions(infections, positions, hexRadius) {
859
863
  const y = normMinY + v * normHeight;
860
864
  return [x, y];
861
865
  };
862
- console.log('[assignClusterGridPositions] Normalized bounds for tiling:', {
866
+ debugLog('[assignClusterGridPositions] Normalized bounds for tiling:', {
863
867
  normMinX: normMinX.toFixed(2),
864
868
  normMinY: normMinY.toFixed(2),
865
869
  normWidth: normWidth.toFixed(2),
@@ -923,8 +927,8 @@ function assignClusterGridPositions(infections, positions, hexRadius) {
923
927
  });
924
928
  }
925
929
  }
926
- console.log('[assignClusterGridPositions] Spatially assigned', cluster.length, 'hexes to nearest tile centers');
927
- console.log('[assignClusterGridPositions] Sample assignments:', assignmentSamples
930
+ debugLog('[assignClusterGridPositions] Spatially assigned', cluster.length, 'hexes to nearest tile centers');
931
+ debugLog('[assignClusterGridPositions] Sample assignments:', assignmentSamples
928
932
  .map((s) => `node#${s.nodeId} at (${s.nodeX.toFixed(1)},${s.nodeY.toFixed(1)}) → tile[${s.tileCol},${s.tileRow}] center(${s.centerX.toFixed(1)},${s.centerY.toFixed(1)}) dist=${s.dist.toFixed(1)}`)
929
933
  .join('\n '));
930
934
  // Optional: Neighborhood-aware refinement to reduce visual seams
@@ -996,7 +1000,7 @@ function assignClusterGridPositions(infections, positions, hexRadius) {
996
1000
  }
997
1001
  if (adjustments === 0)
998
1002
  break; // Converged
999
- console.log('[assignClusterGridPositions] Neighbor-aware refinement iteration', iter + 1, ':', adjustments, 'adjustments');
1003
+ debugLog('[assignClusterGridPositions] Neighbor-aware refinement iteration', iter + 1, ':', adjustments, 'adjustments');
1000
1004
  }
1001
1005
  }
1002
1006
  // Finally write assignments back into infections with UV bounds/inset
@@ -1028,7 +1032,7 @@ function assignClusterGridPositions(infections, positions, hexRadius) {
1028
1032
  tilesY,
1029
1033
  });
1030
1034
  }
1031
- console.log('[assignClusterGridPositions] Assigned grid positions to', cluster.length, 'hexes in cluster (BFS)');
1035
+ debugLog('[assignClusterGridPositions] Assigned grid positions to', cluster.length, 'hexes in cluster (BFS)');
1032
1036
  }
1033
1037
  catch (e) {
1034
1038
  console.error('[assignClusterGridPositions] BFS assignment failed, falling back to quantization', e);
@@ -1044,9 +1048,9 @@ function assignClusterGridPositions(infections, positions, hexRadius) {
1044
1048
  const medianSize = clusterSizes[Math.floor(clusterSizes.length / 2)];
1045
1049
  const maxSize = clusterSizes[0];
1046
1050
  const smallClusters = clusterSizes.filter((s) => s <= 3).length;
1047
- console.log('[assignClusterGridPositions] CLUSTER STATS: total=', totalClusters, 'avg=', avgSize.toFixed(1), 'median=', medianSize, 'max=', maxSize, 'small(≤3)=', smallClusters, '/', totalClusters, '(', ((100 * smallClusters) / totalClusters).toFixed(0), '%)');
1051
+ debugLog('[assignClusterGridPositions] CLUSTER STATS: total=', totalClusters, 'avg=', avgSize.toFixed(1), 'median=', medianSize, 'max=', maxSize, 'small(≤3)=', smallClusters, '/', totalClusters, '(', ((100 * smallClusters) / totalClusters).toFixed(0), '%)');
1048
1052
  }
1049
- console.log('[assignClusterGridPositions] Complete');
1053
+ debugLog('[assignClusterGridPositions] Complete');
1050
1054
  }
1051
1055
  catch (e) {
1052
1056
  console.error('[assignClusterGridPositions] Error:', e);
@@ -1057,7 +1061,7 @@ function postOptimizationMerge(infections, positions, hexRadius, debug = false)
1057
1061
  try {
1058
1062
  if (!workerDebug || !workerDebug.enableMerges) {
1059
1063
  if (debug && workerDebug.mergeLogs)
1060
- console.log('[merge] disabled');
1064
+ debugLog('[merge] disabled');
1061
1065
  return;
1062
1066
  }
1063
1067
  const threshold = typeof workerDebug.mergeSmallComponentsThreshold === 'number'
@@ -1132,7 +1136,7 @@ function postOptimizationMerge(infections, positions, hexRadius, debug = false)
1132
1136
  }
1133
1137
  merges++;
1134
1138
  if (debug && workerDebug.mergeLogs)
1135
- console.log(`[merge] moved ${s.length} -> ${recipientId}`);
1139
+ debugLog(`[merge] moved ${s.length} -> ${recipientId}`);
1136
1140
  }
1137
1141
  }
1138
1142
  }
@@ -1187,36 +1191,36 @@ function normalizePrevState(prevState) {
1187
1191
  }
1188
1192
  function evolveInfectionSystem(prevState, positions, photos, hexRadius, currentTime, debug = false) {
1189
1193
  try {
1190
- console.log('[evolve] Step 1: Validating positions...');
1194
+ debugLog('[evolve] Step 1: Validating positions...');
1191
1195
  if (!positions || positions.length === 0) {
1192
1196
  safePostError(new Error('positions required for evolve'));
1193
1197
  return null;
1194
1198
  }
1195
- console.log('[evolve] Step 2: Normalizing state...');
1199
+ debugLog('[evolve] Step 2: Normalizing state...');
1196
1200
  const normalized = normalizePrevState(prevState);
1197
1201
  const infectionsMap = normalized.infections;
1198
1202
  const availableSet = new Set(Array.isArray(normalized.availableIndices)
1199
1203
  ? normalized.availableIndices
1200
1204
  : []);
1201
- console.log('[evolve] Step 3: Cleaning infections...');
1205
+ debugLog('[evolve] Step 3: Cleaning infections...');
1202
1206
  for (const [idx, inf] of infectionsMap) {
1203
1207
  if (!inf || !inf.photo) {
1204
1208
  infectionsMap.delete(idx);
1205
1209
  availableSet.add(idx);
1206
1210
  }
1207
1211
  }
1208
- console.log('[evolve] Step 4: Calculating centroids...');
1212
+ debugLog('[evolve] Step 4: Calculating centroids...');
1209
1213
  const centroids = calculatePhotoCentroids(infectionsMap, positions, hexRadius);
1210
- console.log('[evolve] Step 5: Creating new state copies...');
1214
+ debugLog('[evolve] Step 5: Creating new state copies...');
1211
1215
  const newInfections = new Map(infectionsMap);
1212
1216
  const newAvailable = new Set(availableSet);
1213
1217
  const generation = prevState && typeof prevState.generation === 'number'
1214
1218
  ? prevState.generation + 1
1215
1219
  : 0;
1216
- console.log('[evolve] Step 6: Growth step - processing', infectionsMap.size, 'infections...');
1220
+ debugLog('[evolve] Step 6: Growth step - processing', infectionsMap.size, 'infections...');
1217
1221
  // Skip growth step if we have no infections or no photos
1218
1222
  if (infectionsMap.size === 0 || photos.length === 0) {
1219
- console.log('[evolve] Skipping growth - no infections or no photos');
1223
+ debugLog('[evolve] Skipping growth - no infections or no photos');
1220
1224
  }
1221
1225
  else {
1222
1226
  // Cell death step: allow fully surrounded cells to die and respawn for optimization
@@ -1351,7 +1355,7 @@ function evolveInfectionSystem(prevState, positions, photos, hexRadius, currentT
1351
1355
  }
1352
1356
  }
1353
1357
  if (deathCount > 0 || mutationCount > 0 || invaderExpulsions > 0) {
1354
- console.log('[evolve] Cell death: removed', deathCount, 'cells (', invaderExpulsions, 'invaders expelled), mutated', mutationCount, 'cells');
1358
+ debugLog('[evolve] Cell death: removed', deathCount, 'cells (', invaderExpulsions, 'invaders expelled), mutated', mutationCount, 'cells');
1355
1359
  }
1356
1360
  }
1357
1361
  // Growth step: prefer neighbors that increase contiguity and are closer to centroids
@@ -1359,7 +1363,7 @@ function evolveInfectionSystem(prevState, positions, photos, hexRadius, currentT
1359
1363
  for (const [idx, inf] of infectionsMap) {
1360
1364
  growthIterations++;
1361
1365
  if (growthIterations % 10 === 0)
1362
- console.log('[evolve] Growth iteration', growthIterations, '/', infectionsMap.size);
1366
+ debugLog('[evolve] Growth iteration', growthIterations, '/', infectionsMap.size);
1363
1367
  const neighbors = getNeighborsCached(idx, positions, hexRadius);
1364
1368
  for (const n of neighbors) {
1365
1369
  if (!newAvailable.has(n))
@@ -1440,7 +1444,7 @@ function evolveInfectionSystem(prevState, positions, photos, hexRadius, currentT
1440
1444
  }
1441
1445
  }
1442
1446
  }
1443
- console.log('[evolve] Step 6.5: Entropy decay - applying decay to dominant successful photos...');
1447
+ debugLog('[evolve] Step 6.5: Entropy decay - applying decay to dominant successful photos...');
1444
1448
  // Entropy decay: successful/dominant photos decay over time to allow new dominance to emerge
1445
1449
  if (workerDebug.enableEntropyDecay && newInfections.size > 0) {
1446
1450
  // Calculate current territory shares
@@ -1524,14 +1528,14 @@ function evolveInfectionSystem(prevState, positions, photos, hexRadius, currentT
1524
1528
  entropyDecayCount++;
1525
1529
  }
1526
1530
  if (entropyDecayCount > 0) {
1527
- console.log('[evolve] Entropy decay: removed', entropyDecayCount, 'cells from dominant successful photos');
1531
+ debugLog('[evolve] Entropy decay: removed', entropyDecayCount, 'cells from dominant successful photos');
1528
1532
  }
1529
1533
  }
1530
1534
  }
1531
- console.log('[evolve] Step 7: Deterministic fill - processing', newAvailable.size, 'available positions...');
1535
+ debugLog('[evolve] Step 7: Deterministic fill - processing', newAvailable.size, 'available positions...');
1532
1536
  // Skip deterministic fill if we have no photos or no existing infections to base decisions on
1533
1537
  if (photos.length === 0 || newInfections.size === 0) {
1534
- console.log('[evolve] Skipping deterministic fill - no photos or no infections');
1538
+ debugLog('[evolve] Skipping deterministic fill - no photos or no infections');
1535
1539
  }
1536
1540
  else {
1537
1541
  // Deterministic fill for holes with >=2 same-photo neighbors
@@ -1539,7 +1543,7 @@ function evolveInfectionSystem(prevState, positions, photos, hexRadius, currentT
1539
1543
  for (const a of Array.from(newAvailable)) {
1540
1544
  fillIterations++;
1541
1545
  if (fillIterations % 50 === 0)
1542
- console.log('[evolve] Fill iteration', fillIterations, '/', newAvailable.size);
1546
+ debugLog('[evolve] Fill iteration', fillIterations, '/', newAvailable.size);
1543
1547
  const neighbors = getNeighborsCached(a, positions, hexRadius);
1544
1548
  const counts = new Map();
1545
1549
  for (const n of neighbors) {
@@ -1578,13 +1582,13 @@ function evolveInfectionSystem(prevState, positions, photos, hexRadius, currentT
1578
1582
  }
1579
1583
  }
1580
1584
  }
1581
- console.log('[evolve] Step 8: Optimization merge pass...');
1585
+ debugLog('[evolve] Step 8: Optimization merge pass...');
1582
1586
  // Conservative merge pass (opt-in)
1583
1587
  postOptimizationMerge(newInfections, positions, hexRadius, !!workerDebug.mergeLogs);
1584
- console.log('[evolve] Step 9: Assigning cluster-aware grid positions...');
1588
+ debugLog('[evolve] Step 9: Assigning cluster-aware grid positions...');
1585
1589
  // Make clusters self-aware by assigning grid positions based on spatial layout
1586
1590
  const tileCenters = assignClusterGridPositions(newInfections, positions, hexRadius);
1587
- console.log('[evolve] Step 10: Returning result - generation', generation, 'infections', newInfections.size);
1591
+ debugLog('[evolve] Step 10: Returning result - generation', generation, 'infections', newInfections.size);
1588
1592
  return {
1589
1593
  infections: newInfections,
1590
1594
  availableIndices: Array.from(newAvailable),
@@ -1637,7 +1641,7 @@ self.onmessage = function (ev) {
1637
1641
  if (!positions || !Array.isArray(positions))
1638
1642
  return;
1639
1643
  const hexRadius = typeof payload.hexRadius === 'number' ? payload.hexRadius : 24;
1640
- console.log('[hexgrid-worker] Pre-building neighbor cache for', positions.length, 'positions...');
1644
+ debugLog('[hexgrid-worker] Pre-building neighbor cache for', positions.length, 'positions...');
1641
1645
  const startTime = Date.now();
1642
1646
  // Build ALL neighbor relationships in one O(n²) pass instead of n×O(n) passes
1643
1647
  try {
@@ -1667,11 +1671,11 @@ self.onmessage = function (ev) {
1667
1671
  }
1668
1672
  // Log progress every 100 positions
1669
1673
  if ((i + 1) % 100 === 0) {
1670
- console.log('[hexgrid-worker] Processed', i + 1, '/', positions.length, 'positions');
1674
+ debugLog('[hexgrid-worker] Processed', i + 1, '/', positions.length, 'positions');
1671
1675
  }
1672
1676
  }
1673
1677
  const elapsed = Date.now() - startTime;
1674
- console.log('[hexgrid-worker] ✅ Neighbor cache built in', elapsed, 'ms - ready for evolution!');
1678
+ debugLog('[hexgrid-worker] ✅ Neighbor cache built in', elapsed, 'ms - ready for evolution!');
1675
1679
  // Mark cache as ready
1676
1680
  cache.cacheReady = true;
1677
1681
  // Notify main thread that cache is ready
@@ -1694,7 +1698,7 @@ self.onmessage = function (ev) {
1694
1698
  if (type === 'evolve') {
1695
1699
  // Check if neighbor cache is ready before processing evolve
1696
1700
  if (!cache.cacheReady) {
1697
- console.log('[hexgrid-worker] ⏸️ Evolve message received but cache not ready yet - deferring...');
1701
+ debugLog('[hexgrid-worker] ⏸️ Evolve message received but cache not ready yet - deferring...');
1698
1702
  // Defer this evolve message by re-posting it after a short delay
1699
1703
  setTimeout(() => {
1700
1704
  try {
@@ -1714,7 +1718,7 @@ self.onmessage = function (ev) {
1714
1718
  // Diagnostic: log that an evolve was received and the available payload keys (only when debugLogs enabled)
1715
1719
  try {
1716
1720
  if (workerDebug && workerDebug.debugLogs) {
1717
- console.log('[hexgrid-worker] evolve received, payload keys=', Object.keys(payload || {}), 'workerDebug.evolutionIntervalMs=', workerDebug.evolutionIntervalMs, 'workerDebug.evolveIntervalMs=', workerDebug.evolveIntervalMs);
1721
+ debugLog('[hexgrid-worker] evolve received, payload keys=', Object.keys(payload || {}), 'workerDebug.evolutionIntervalMs=', workerDebug.evolutionIntervalMs, 'workerDebug.evolveIntervalMs=', workerDebug.evolveIntervalMs);
1718
1722
  }
1719
1723
  }
1720
1724
  catch (e) { }
@@ -1724,12 +1728,12 @@ self.onmessage = function (ev) {
1724
1728
  : typeof workerDebug.evolveIntervalMs === 'number'
1725
1729
  ? workerDebug.evolveIntervalMs
1726
1730
  : 60000;
1727
- console.log('[hexgrid-worker] Throttle check: interval=', interval, 'lastEvolutionAt=', lastEvolutionAt, 'now=', now, 'diff=', now - lastEvolutionAt, 'willThrottle=', now - lastEvolutionAt < interval);
1731
+ debugLog('[hexgrid-worker] Throttle check: interval=', interval, 'lastEvolutionAt=', lastEvolutionAt, 'now=', now, 'diff=', now - lastEvolutionAt, 'willThrottle=', now - lastEvolutionAt < interval);
1728
1732
  // Throttle: if we're within the interval, notify (debug) and skip processing
1729
1733
  const reason = payload.reason || (raw && raw.reason);
1730
1734
  const bypassThrottle = reason === 'photos-init' || reason === 'reset';
1731
1735
  // Clear, high-signal log for build verification: reports whether the current evolve will bypass the worker throttle
1732
- console.log('[hexgrid-worker] THROTTLE DECISION', {
1736
+ debugLog('[hexgrid-worker] THROTTLE DECISION', {
1733
1737
  interval,
1734
1738
  lastEvolutionAt,
1735
1739
  now,
@@ -1740,7 +1744,7 @@ self.onmessage = function (ev) {
1740
1744
  });
1741
1745
  // Throttle: if we're within the interval and not bypassed, notify (debug) and skip processing
1742
1746
  if (!bypassThrottle && now - lastEvolutionAt < interval) {
1743
- console.log('[hexgrid-worker] ⛔ THROTTLED - skipping evolution processing');
1747
+ debugLog('[hexgrid-worker] ⛔ THROTTLED - skipping evolution processing');
1744
1748
  if (workerDebug && workerDebug.debugLogs) {
1745
1749
  try {
1746
1750
  self.postMessage({
@@ -1759,7 +1763,7 @@ self.onmessage = function (ev) {
1759
1763
  }
1760
1764
  // Mark processed time and send ack for an evolve we will process
1761
1765
  lastEvolutionAt = now;
1762
- console.log('[hexgrid-worker] ✅ PROCESSING evolution - lastEvolutionAt updated to', now);
1766
+ debugLog('[hexgrid-worker] ✅ PROCESSING evolution - lastEvolutionAt updated to', now);
1763
1767
  try {
1764
1768
  if (workerDebug && workerDebug.debugLogs) {
1765
1769
  try {
@@ -1800,12 +1804,12 @@ self.onmessage = function (ev) {
1800
1804
  Boolean(payload.isSpherical) !== cache.isSpherical) {
1801
1805
  invalidateCaches(Boolean(payload.isSpherical));
1802
1806
  }
1803
- console.log('[hexgrid-worker] 🔧 About to call evolveInfectionSystem');
1804
- console.log('[hexgrid-worker] - state generation:', state?.generation);
1805
- console.log('[hexgrid-worker] - state infections:', state?.infections?.length || state?.infections?.size || 0);
1806
- console.log('[hexgrid-worker] - positions:', positions?.length || 0);
1807
- console.log('[hexgrid-worker] - photos:', photos?.length || 0);
1808
- console.log('[hexgrid-worker] - hexRadius:', hexRadius);
1807
+ debugLog('[hexgrid-worker] 🔧 About to call evolveInfectionSystem');
1808
+ debugLog('[hexgrid-worker] - state generation:', state?.generation);
1809
+ debugLog('[hexgrid-worker] - state infections:', state?.infections?.length || state?.infections?.size || 0);
1810
+ debugLog('[hexgrid-worker] - positions:', positions?.length || 0);
1811
+ debugLog('[hexgrid-worker] - photos:', photos?.length || 0);
1812
+ debugLog('[hexgrid-worker] - hexRadius:', hexRadius);
1809
1813
  let res;
1810
1814
  let timeoutId;
1811
1815
  let timedOut = false;
@@ -1822,12 +1826,12 @@ self.onmessage = function (ev) {
1822
1826
  catch (e) { }
1823
1827
  }, 10000);
1824
1828
  try {
1825
- console.log('[hexgrid-worker] 🚀 Calling evolveInfectionSystem NOW...');
1829
+ debugLog('[hexgrid-worker] 🚀 Calling evolveInfectionSystem NOW...');
1826
1830
  const startTime = Date.now();
1827
1831
  res = evolveInfectionSystem(state, positions, photos, hexRadius, now, !!workerDebug.debugLogs);
1828
1832
  const elapsed = Date.now() - startTime;
1829
1833
  clearTimeout(timeoutId);
1830
- console.log('[hexgrid-worker] ✅ evolveInfectionSystem RETURNED successfully in', elapsed, 'ms');
1834
+ debugLog('[hexgrid-worker] ✅ evolveInfectionSystem RETURNED successfully in', elapsed, 'ms');
1831
1835
  }
1832
1836
  catch (err) {
1833
1837
  clearTimeout(timeoutId);
@@ -1840,10 +1844,10 @@ self.onmessage = function (ev) {
1840
1844
  console.error('[hexgrid-worker] ⏱️ Function eventually returned but after timeout was triggered');
1841
1845
  }
1842
1846
  if (!res) {
1843
- console.log('[hexgrid-worker] ❌ evolveInfectionSystem returned null!');
1847
+ debugLog('[hexgrid-worker] ❌ evolveInfectionSystem returned null!');
1844
1848
  return;
1845
1849
  }
1846
- console.log('[hexgrid-worker] ✅ Evolution complete! New generation=', res.generation, 'infections=', res.infections.size);
1850
+ debugLog('[hexgrid-worker] ✅ Evolution complete! New generation=', res.generation, 'infections=', res.infections.size);
1847
1851
  try {
1848
1852
  const payload = {
1849
1853
  infections: Array.from(res.infections.entries()),
@@ -1853,7 +1857,7 @@ self.onmessage = function (ev) {
1853
1857
  };
1854
1858
  if (res.tileCenters && res.tileCenters.length > 0) {
1855
1859
  payload.tileCenters = res.tileCenters;
1856
- console.log('[hexgrid-worker] Including', res.tileCenters.length, 'tile center sets in evolved message');
1860
+ debugLog('[hexgrid-worker] Including', res.tileCenters.length, 'tile center sets in evolved message');
1857
1861
  }
1858
1862
  self.postMessage({ type: 'evolved', data: payload });
1859
1863
  // Record posted generation/infection count so later auto-triggers can avoid regressing
@@ -1866,7 +1870,7 @@ self.onmessage = function (ev) {
1866
1870
  catch (e) {
1867
1871
  console.error('[hexgrid-worker] ❌ Failed to post evolved message:', e);
1868
1872
  }
1869
- console.log('[hexgrid-worker] 📤 Posted evolved message back to main thread');
1873
+ debugLog('[hexgrid-worker] 📤 Posted evolved message back to main thread');
1870
1874
  // Emit a completion marker so the client can confirm the evolve finished end-to-end
1871
1875
  try {
1872
1876
  if (workerDebug && workerDebug.debugLogs) {
@@ -2011,4 +2015,4 @@ function invalidateCaches(isSpherical) {
2011
2015
  if (typeof isSpherical === 'boolean')
2012
2016
  cache.isSpherical = isSpherical;
2013
2017
  }
2014
- console.log('[hexgrid-worker] ready');
2018
+ debugLog('[hexgrid-worker] ready');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buley/hexgrid-3d",
3
- "version": "3.4.0",
3
+ "version": "3.5.0",
4
4
  "description": "3D hexagonal grid visualization component for React",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",