@navaramap/three 0.0.1 → 0.0.2

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 (54) hide show
  1. package/README.md +70 -0
  2. package/dist/assets/fontWorker-8oWvyvwL.js +2 -0
  3. package/dist/assets/fontWorker-8oWvyvwL.js.map +1 -0
  4. package/dist/assets/index-D9G7kIEj.js +25 -0
  5. package/dist/assets/index-D9G7kIEj.js.map +1 -0
  6. package/dist/assets/{navara_wasm_font_worker_bg-Bnck8OGf.wasm → navara_wasm_font_worker_bg-CkZP9l2i.wasm} +0 -0
  7. package/dist/assets/{navara_wasm_worker_bg-DG9ORAmj.wasm → navara_wasm_worker_bg-Q8zrkLCR.wasm} +0 -0
  8. package/dist/draco_decoder.wasm +0 -0
  9. package/dist/draco_decoder2.wasm +0 -0
  10. package/dist/index.d.ts +445 -16
  11. package/dist/index.js +6151 -5717
  12. package/dist/index.js.map +1 -1
  13. package/dist/index.umd.cjs +241 -222
  14. package/dist/index.umd.cjs.map +1 -1
  15. package/package.json +34 -33
  16. package/src/core/EffectDesc.ts +2 -4
  17. package/src/core/MeshDesc.ts +1 -2
  18. package/src/core/MeshDescWithSelectiveEffect.ts +1 -2
  19. package/src/declutter/DeclutterManager.test.ts +235 -0
  20. package/src/declutter/DeclutterManager.ts +256 -0
  21. package/src/declutter/index.ts +7 -0
  22. package/src/declutter/kernel.ts +46 -0
  23. package/src/declutter/types.ts +61 -0
  24. package/src/declutter/wasmKernel.ts +13 -0
  25. package/src/device.ts +18 -4
  26. package/src/evaluations/FeatureEvaluator.ts +21 -0
  27. package/src/event/context.ts +12 -0
  28. package/src/event/features/modelGpuBytes.ts +1 -3
  29. package/src/event/hillshade.test.ts +7 -13
  30. package/src/event/index.ts +2 -3
  31. package/src/event/tileHandler.ts +54 -0
  32. package/src/index.ts +137 -35
  33. package/src/material/enhancer/ShaderReplacer.ts +1 -2
  34. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/mutates.ts +6 -0
  35. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/types.ts +11 -0
  36. package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/mutates.test.ts +83 -0
  37. package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/mutates.ts +13 -3
  38. package/src/mesh/batchTexture.ts +2 -4
  39. package/src/mesh/batchedSdfText.ts +61 -1
  40. package/src/mesh/sdfText.ts +170 -5
  41. package/src/mesh/sprite/instancedSprite.ts +245 -3
  42. package/src/orchestrators/RenderPassOrchestrator.ts +25 -0
  43. package/src/passes/CustomRenderPass.ts +21 -5
  44. package/src/passes/RenderTargetCopyPass.ts +24 -2
  45. package/src/test-utils/engine.ts +53 -0
  46. package/src/tileTexture/TileTextureCompositor.test.ts +2 -0
  47. package/src/tileTexture/TileTextureCompositor.ts +7 -1
  48. package/src/utils/fixedGpuFootprint.test.ts +110 -0
  49. package/src/utils/fixedGpuFootprint.ts +162 -0
  50. package/src/worker/tasks/toCreasedNormals.ts +2 -7
  51. package/dist/assets/fontWorker-CCWL5pbx.js +0 -2
  52. package/dist/assets/fontWorker-CCWL5pbx.js.map +0 -1
  53. package/dist/assets/index-BdtHOOT9.js +0 -12
  54. package/dist/assets/index-BdtHOOT9.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -863,7 +863,7 @@ export declare class BatchedFeatureMesh<Buf extends BufferGeometry<BatchedFeatur
863
863
  clone(): this;
864
864
  }
865
865
 
866
- export declare class BatchedSdfTextMesh extends InstancedMesh<SDFTextMesh> implements PickableMesh {
866
+ export declare class BatchedSdfTextMesh extends InstancedMesh<SDFTextMesh> implements PickableMesh, DeclutterParticipant {
867
867
  readonly ctx: EventContext;
868
868
  /** The font identifier from material — may be a family name or a URL. */
869
869
  private _fontIdentifier;
@@ -882,6 +882,13 @@ export declare class BatchedSdfTextMesh extends InstancedMesh<SDFTextMesh> imple
882
882
  */
883
883
  private _loadedFaceUrls;
884
884
  constructor(ctx: EventContext, m: TextMesh, fontIdentifier: string, options: InstancedMeshOptions, loadedFaceUrls?: Set<string>);
885
+ collectDeclutterCandidates(out: DeclutterCandidate[]): void;
886
+ applyDeclutter(handle: number, hidden: boolean): void;
887
+ stepDeclutterFade(deltaMs: number): boolean;
888
+ /** Candidates changed (text, style, position, visibility): ask the shared
889
+ * declutter pass to re-place on its next update. */
890
+ private _markDeclutterDirty;
891
+ setActive(active: boolean): void;
885
892
  /**
886
893
  * After an atlas eviction, re-prepare and force-rebuild any visible mesh whose
887
894
  * shaped text is now stale (its pinned glyphs may have been evicted before the
@@ -902,6 +909,7 @@ export declare class BatchedSdfTextMesh extends InstancedMesh<SDFTextMesh> imple
902
909
  setFeatureShowByBatchIndex(batchIndex: number, rawVisible: boolean): void;
903
910
  setFeatureHeightByBatchIndex(batchIndex: number, height: number): void;
904
911
  setFeatureSizeByBatchIndex(batchIndex: number, size: number): void;
912
+ setFeatureDeclutterPriorityByBatchIndex(batchIndex: number, priority: number): void;
905
913
  setFeatureOpacityByBatchIndex(batchIndex: number, opacity: number): void;
906
914
  dispose(): void;
907
915
  }
@@ -951,6 +959,28 @@ declare class BillboardMaterial {
951
959
  set clampToGround(value: boolean | null | undefined);
952
960
  get color(): number | undefined;
953
961
  set color(value: number | null | undefined);
962
+ /**
963
+ * Placement priority for decluttering; higher wins. Only meaningful when
964
+ * `declutter` is enabled. Defaults to `0.0`.
965
+ */
966
+ get declutterPriority(): number | undefined;
967
+ /**
968
+ * Placement priority for decluttering; higher wins. Only meaningful when
969
+ * `declutter` is enabled. Defaults to `0.0`.
970
+ */
971
+ set declutterPriority(value: number | null | undefined);
972
+ /**
973
+ * Participate in screen-space decluttering: when labels/sprites overlap
974
+ * on screen, lower-priority ones are hidden. Defaults to `true`; set to
975
+ * `false` to draw every label unconditionally.
976
+ */
977
+ get declutter(): boolean | undefined;
978
+ /**
979
+ * Participate in screen-space decluttering: when labels/sprites overlap
980
+ * on screen, lower-priority ones are hidden. Defaults to `true`; set to
981
+ * `false` to draw every label unconditionally.
982
+ */
983
+ set declutter(value: boolean | null | undefined);
954
984
  get depthTest(): boolean | undefined;
955
985
  set depthTest(value: boolean | null | undefined);
956
986
  /**
@@ -1868,6 +1898,13 @@ declare class Core {
1868
1898
  */
1869
1899
  setDynamicSse(settings: DynamicSse): void;
1870
1900
  setExternalBuffer(handle: number, bits: bigint, byte_length: number): void;
1901
+ /**
1902
+ * Reports the estimated GPU bytes of fixed, screen-sized allocations
1903
+ * (the postprocessing render-target stack). Counted in the ledger's
1904
+ * usage so the tile budget binds against the remaining memory. The JS
1905
+ * side re-reports on init, resize, and pass-list changes.
1906
+ */
1907
+ setFixedGpuBytes(bytes: number): void;
1871
1908
  setFrustum(fov?: number | null, near?: number | null, far?: number | null): void;
1872
1909
  setGlobeColor(value: number): void;
1873
1910
  setGlobeElevationColormap(value: Float32Array): void;
@@ -2175,7 +2212,7 @@ export declare class CustomRenderPass extends RenderPass {
2175
2212
  constructor(scenes: Scenes, camera: PerspectiveCamera, inputBuffer: WebGLRenderTarget, globe: Globe, options?: CustomRenderPassOptions);
2176
2213
  protected _renderWithLight(renderer: WebGLRenderer, scene: Scene): void;
2177
2214
  render(renderer: WebGLRenderer, inputBuffer: WebGLRenderTarget | null, _outputBuffer: WebGLRenderTarget | null): void;
2178
- setDepthTexture(depthTexture: DepthTexture): void;
2215
+ setDepthTexture(): void;
2179
2216
  setSize(width: number, height: number): void;
2180
2217
  protected _renderDrapedMesh(renderer: WebGLRenderer): void;
2181
2218
  }
@@ -2245,6 +2282,179 @@ declare class DataRequestEvent {
2245
2282
  url: string;
2246
2283
  }
2247
2284
 
2285
+ /**
2286
+ * One label/sprite competing for screen space in a declutter pass.
2287
+ *
2288
+ * The local box is expressed around the projected anchor in the shader's
2289
+ * billboard-local units — CSS pixels when `sizeInMeters` is false, meters
2290
+ * otherwise — with +X right and +Y up (view-space convention). The manager
2291
+ * converts it to a screen-pixel AABB using the same `nvr_pxToWorld` math the
2292
+ * vertex shaders use, so the collision box matches what is actually drawn.
2293
+ */
2294
+ declare type DeclutterCandidate = {
2295
+ /** World-space anchor in ECEF meters (f64), before the height offset. */
2296
+ anchorX: number;
2297
+ anchorY: number;
2298
+ anchorZ: number;
2299
+ /** Extra offset in meters along the spherical surface normal — CPU mirror
2300
+ * of `mvr_getMvHeightOffset` (sprite_height_pars_vertex.glsl). */
2301
+ addHeight: number;
2302
+ /** Local box around the anchor (px or meters, see `sizeInMeters`). */
2303
+ minX: number;
2304
+ maxX: number;
2305
+ minY: number;
2306
+ maxY: number;
2307
+ /** Unit of the local box, mirroring the material's `sizeInMeters`. */
2308
+ sizeInMeters: boolean;
2309
+ /** Placement priority: higher wins an overlap. */
2310
+ priority: number;
2311
+ /** Whether the label is currently shown (its fade target is "visible").
2312
+ * Feeds placement hysteresis: shown labels win equal-priority ties and
2313
+ * tolerate marginal overlaps, so slow camera drift doesn't make near-tied
2314
+ * labels flicker in and out. */
2315
+ isShown: boolean;
2316
+ /** Participant that owns this candidate; receives the placement result. */
2317
+ owner: DeclutterParticipant;
2318
+ /** Participant-defined id (mesh index for text batches, instance index for
2319
+ * sprites) passed back to `applyDeclutter`. */
2320
+ handle: number;
2321
+ };
2322
+
2323
+ /**
2324
+ * The pure numeric placement kernel used by {@link DeclutterManager}.
2325
+ *
2326
+ * Given a flat list of candidates and the camera, it projects each anchor to a
2327
+ * screen-pixel box, sorts by priority (with placement hysteresis), and greedily
2328
+ * claims space in a uniform screen-space grid — returning one `hidden` flag
2329
+ * (`0` = shown, `1` = hidden) per candidate, in input order.
2330
+ *
2331
+ * The production implementation is the Rust `declutterPlace` in
2332
+ * `navara_wasm_api` (see {@link wasmDeclutterKernel}); the projection, collision
2333
+ * grid, and greedy placement all live there. Injecting it keeps the manager free
2334
+ * of an import-time WASM dependency, so its orchestration is unit-tested with a
2335
+ * stub. Placement correctness itself is covered by the crate's Rust tests.
2336
+ */
2337
+ declare type DeclutterKernel = {
2338
+ /**
2339
+ * @param candidates Packed `f64` data, {@link CANDIDATE_STRIDE} values per
2340
+ * candidate; pass a subarray of exactly `n * CANDIDATE_STRIDE`.
2341
+ * @param view Column-major view matrix (inverse of `camera.matrixWorld`), 16.
2342
+ * @param proj Column-major projection matrix, 16.
2343
+ * @returns One `hidden` flag (`0`/`1`) per candidate, in input order.
2344
+ */
2345
+ place(candidates: Float64Array, view: Float64Array, proj: Float64Array, cameraX: number, cameraY: number, cameraZ: number, near: number, widthPx: number, heightPx: number, fovRad: number, paddingPx: number, hysteresisPx: number): Uint8Array;
2346
+ };
2347
+
2348
+ /**
2349
+ * Shared screen-space label decluttering.
2350
+ *
2351
+ * Text batches and sprite meshes register as participants; each placement
2352
+ * pass packs every candidate label into a flat buffer and hands it to the
2353
+ * Rust {@link DeclutterKernel}, which projects the anchors, sorts by priority,
2354
+ * and greedily claims screen space — losers are hidden through the meshes'
2355
+ * declutter channels (`uDeclutterHide` uniform / `instanceDeclutterHide`
2356
+ * attribute), which are separate from user-driven `show` state and free to
2357
+ * toggle every pass.
2358
+ *
2359
+ * Placement is hysteretic: currently-shown labels win equal-priority ties
2360
+ * and tolerate {@link DeclutterManager.HYSTERESIS_PX} of marginal overlap
2361
+ * before eviction, so near-ties don't flicker while the camera drifts.
2362
+ *
2363
+ * The pass is view-dependent, so it runs from the render loop — but throttled:
2364
+ * placement only re-runs when the camera or the label set actually changed,
2365
+ * and at most once per {@link DeclutterManager.MIN_INTERVAL_MS}. Callers run
2366
+ * it *before* rendering so results land in the same frame.
2367
+ */
2368
+ declare class DeclutterManager {
2369
+ private readonly _kernel;
2370
+ /** Minimum time between placement passes (ms). */
2371
+ static readonly MIN_INTERVAL_MS = 150;
2372
+ /** Padding added around every collision box (px); two labels never sit
2373
+ * closer than twice this. */
2374
+ static readonly PADDING_PX = 2;
2375
+ /** Largest single fade step (ms), so a frame after an idle gap doesn't
2376
+ * swallow most of a fade in one jump. */
2377
+ static readonly MAX_FADE_STEP_MS = 50;
2378
+ /** Placement hysteresis (px): a currently-shown label's collision test box
2379
+ * shrinks by this per side, so it survives marginal overlaps that camera
2380
+ * drift toggles frame to frame instead of flickering. Its full box is
2381
+ * still claimed against competitors. */
2382
+ static readonly HYSTERESIS_PX = 6;
2383
+ private _participants;
2384
+ /** Set when the label set changed (register/update/text change) so the next
2385
+ * update re-places even with a static camera. */
2386
+ private _dirty;
2387
+ private _prevCamera;
2388
+ private _lastRunAt;
2389
+ private _lastStepAt;
2390
+ private _candidates;
2391
+ /** Packed candidate input for the kernel; grows as the label count does. */
2392
+ private _input;
2393
+ private _viewMatrix;
2394
+ private _view16;
2395
+ private _proj16;
2396
+ /** @param _kernel the placement kernel — the Rust-backed
2397
+ * `wasmDeclutterKernel` in production, a stub in unit tests. */
2398
+ constructor(_kernel: DeclutterKernel);
2399
+ /** Milliseconds until the throttle window since the last placement pass
2400
+ * elapses, clamped to `[0, MIN_INTERVAL_MS]`. Callers use this to schedule
2401
+ * a follow-up frame after a `"throttled"` result without overshooting the
2402
+ * window by waiting out the full constant from now. */
2403
+ remainingThrottleMs(nowMs: number): number;
2404
+ register(participant: DeclutterParticipant): void;
2405
+ unregister(participant: DeclutterParticipant): void;
2406
+ /** Signal that candidates changed (text, positions, visibility, style) so
2407
+ * the next update re-runs placement even if the camera is still. */
2408
+ markDirty(): void;
2409
+ /**
2410
+ * Run a placement pass if one is due, then advance any active show/hide
2411
+ * fades. `widthPx`/`heightPx` are the viewport in CSS pixels (matching the
2412
+ * `uScreenHeightPx` uniform); `nowMs` is the frame timestamp used for
2413
+ * throttling and fade stepping.
2414
+ */
2415
+ update(camera: PerspectiveCamera, widthPx: number, heightPx: number, nowMs: number): DeclutterUpdateResult;
2416
+ private _run;
2417
+ /** Drop all registered participants. Call when the owning view is disposed
2418
+ * so this manager doesn't keep strong references to removed meshes (and
2419
+ * their GPU/font resources) past the view's lifetime. */
2420
+ dispose(): void;
2421
+ private _snapshotChanged;
2422
+ private _takeSnapshot;
2423
+ }
2424
+
2425
+ /** A mesh that contributes label candidates to the shared declutter pass. */
2426
+ declare type DeclutterParticipant = {
2427
+ /**
2428
+ * Append the currently-visible, declutter-enabled candidates to `out`.
2429
+ * Called once per placement pass; must not retain `out`.
2430
+ */
2431
+ collectDeclutterCandidates: (out: DeclutterCandidate[]) => void;
2432
+ /**
2433
+ * Apply a placement result as the label's fade *target*. Must be cheap and
2434
+ * idempotent — the pass calls it for every candidate on every run, most
2435
+ * often with an unchanged value.
2436
+ */
2437
+ applyDeclutter: (handle: number, hidden: boolean) => void;
2438
+ /**
2439
+ * Advance this participant's hide factors toward their targets by
2440
+ * `deltaMs / DECLUTTER_FADE_MS`. Called by the manager every update while
2441
+ * anything is fading; returns true while any label is still mid-fade.
2442
+ */
2443
+ stepDeclutterFade: (deltaMs: number) => boolean;
2444
+ };
2445
+
2446
+ declare type DeclutterUpdateResult =
2447
+ /** Nothing to do: no participants, or camera and data unchanged. */
2448
+ "idle"
2449
+ /** A placement pass ran; results are applied to the participants. */
2450
+ | "ran"
2451
+ /** Labels are mid-fade — the caller should schedule a prompt follow-up
2452
+ * frame so the animation keeps stepping. */
2453
+ | "animating"
2454
+ /** A pass is due but the throttle window hasn't elapsed — the caller should
2455
+ * schedule another frame so placement settles after the camera stops. */
2456
+ | "throttled";
2457
+
2248
2458
  export declare const DEFAULT_EFFECT_OPTIONS: Required<EffectOptions>;
2249
2459
 
2250
2460
  export declare type DefaultBatchAttributeValues = {
@@ -2854,6 +3064,9 @@ export declare type EvaluatableMaterialProperty = {
2854
3064
  size: AvailableMaterialProperty["size"];
2855
3065
  /** Opacity expression from layer configuration (for polygons/points/text where supported). */
2856
3066
  opacity: AvailableMaterialProperty["opacity"];
3067
+ /** Per-feature declutter placement priority (for points/billboards/text);
3068
+ * higher wins an overlap. Overrides the layer's `declutterPriority`. */
3069
+ declutterPriority: AvailableMaterialProperty["declutterPriority"];
2857
3070
  /** Image URL for billboards; packed into a shared per-mesh texture atlas. */
2858
3071
  image: string;
2859
3072
  };
@@ -2869,6 +3082,7 @@ declare type EvaluatedMaterialProperty = {
2869
3082
  width: number;
2870
3083
  size: number;
2871
3084
  opacity: number;
3085
+ declutterPriority: number;
2872
3086
  image: string | null;
2873
3087
  };
2874
3088
 
@@ -2912,6 +3126,9 @@ declare class EventContext {
2912
3126
  readonly textureFragmentIndex?: Map<string, Set<TextureSlot>>;
2913
3127
  readonly tileMeshToFragmentIds?: Map<TileMesh, Set<string>>;
2914
3128
  readonly hillshadeContext?: HillshadeContext;
3129
+ /** Shared screen-space label declutterer; text/sprite meshes register as
3130
+ * participants on creation. Optional so headless contexts can skip it. */
3131
+ readonly declutter?: DeclutterManager;
2915
3132
  updatedAt: number;
2916
3133
  constructor(args: EventContextArgs);
2917
3134
  }
@@ -2944,6 +3161,7 @@ declare type EventContextArgs = {
2944
3161
  textureFragmentIndex?: Map<string, Set<TextureSlot>>;
2945
3162
  tileMeshToFragmentIds?: Map<TileMesh, Set<string>>;
2946
3163
  hillshadeContext?: HillshadeContext;
3164
+ declutter?: DeclutterManager;
2947
3165
  };
2948
3166
 
2949
3167
  export declare class EventHandler<T extends BaseEventMap = BaseEventMap, K extends keyof T = keyof T> {
@@ -3146,6 +3364,8 @@ export declare class FeatureEvaluator {
3146
3364
  * - `width` - Line width in pixels (for polylines)
3147
3365
  * - `size` - Feature size in pixels (for points/text)
3148
3366
  * - `opacity` - Feature opacity 0-1
3367
+ * - `declutterPriority` - Placement priority for decluttering; higher wins
3368
+ * an overlap (for points/billboards/text with `declutter` enabled)
3149
3369
  * - `image` - Image URL (for billboards); loaded once per distinct URL and
3150
3370
  * packed into the layer's texture atlas. Return `null` to clear a
3151
3371
  * previous per-feature image and revert to the material's default `url`;
@@ -4044,7 +4264,7 @@ export declare type InstancedSpriteMaterialProps = {
4044
4264
  base?: InstancedSpriteBaseProps;
4045
4265
  };
4046
4266
 
4047
- export declare class InstancedSpriteMesh extends Mesh_2 implements PickableMesh {
4267
+ export declare class InstancedSpriteMesh extends Mesh_2<BufferGeometry, Material | Material[], CustomObject3DEventMap> implements PickableMesh, DeclutterParticipant {
4048
4268
  private _batchIdToInstance;
4049
4269
  private _initialColor;
4050
4270
  private _initialHeight;
@@ -4068,8 +4288,31 @@ export declare class InstancedSpriteMesh extends Mesh_2 implements PickableMesh
4068
4288
  readonly ctx: EventContext;
4069
4289
  /** Material enhancer for encapsulated state management */
4070
4290
  private _enhancedMaterial?;
4291
+ /** Per-instance world anchors in ECEF meters (f64, 3 per instance), kept in
4292
+ * sync with the position attributes for the declutter pass. */
4293
+ private _anchors;
4294
+ /** Whether this mesh's instances participate in screen-space decluttering. */
4295
+ private _declutter;
4296
+ /** Layer-level placement priority from the material. */
4297
+ private _declutterPriority;
4298
+ /** Per-instance priorities set through the evaluator (NaN = no override,
4299
+ * fall back to the layer value). Lazily allocated on first use. */
4300
+ private _declutterPriorityOverrides;
4301
+ /** Per-instance fade targets for `instanceDeclutterHide` (0 = shown,
4302
+ * 1 = hidden); the attribute animates toward these in stepDeclutterFade. */
4303
+ private _declutterTargets;
4304
+ /** True while any instance's hide factor may differ from its target. */
4305
+ private _declutterAnimating;
4071
4306
  constructor(options: InstancedSpriteOptions);
4072
4307
  setActive(active: boolean): void;
4308
+ collectDeclutterCandidates(out: DeclutterCandidate[]): void;
4309
+ applyDeclutter(handle: number, hidden: boolean): void;
4310
+ stepDeclutterFade(deltaMs: number): boolean;
4311
+ private _cacheDeclutterState;
4312
+ private _clearDeclutterHidden;
4313
+ /** Reconstruct absolute ECEF anchors from the same arrays the position
4314
+ * attributes receive (RTE high+low split, or RTC-relative + center). */
4315
+ private _cacheAnchors;
4073
4316
  _init(m: PointMesh | BillboardMesh): Promise<void>;
4074
4317
  _update(m: PointMesh | BillboardMesh): Promise<void>;
4075
4318
  private _initGeometry;
@@ -4109,6 +4352,19 @@ export declare class InstancedSpriteMesh extends Mesh_2 implements PickableMesh
4109
4352
  setFeatureShowByBatchId(batchId: number, rawVisible: boolean): void;
4110
4353
  setFeatureOpacityByBatchId(batchId: number, opacity: number): void;
4111
4354
  setFeatureHeightByBatchId(batchId: number, height: number): void;
4355
+ /**
4356
+ * Set one instance's declutter fade target; the attribute animates toward
4357
+ * it in {@link stepDeclutterFade}. Deliberately separate from the `show`
4358
+ * component of `instanceParams` so user-driven visibility and declutter
4359
+ * results compose instead of clobbering each other.
4360
+ */
4361
+ setDeclutterHiddenByInstance(instanceIndex: number, hidden: boolean): void;
4362
+ /**
4363
+ * Set a per-feature placement priority (higher wins), overriding the
4364
+ * layer-level `declutterPriority` for this instance. Driven by the feature
4365
+ * evaluator.
4366
+ */
4367
+ setFeatureDeclutterPriorityByBatchId(batchId: number, priority: number): void;
4112
4368
  setFeatureSizeByBatchId(batchId: number, size: number): void;
4113
4369
  /**
4114
4370
  * Give one feature its own image, packed into this mesh's texture atlas.
@@ -4241,7 +4497,7 @@ declare type LayerId = string;
4241
4497
  declare class LayersManager {
4242
4498
  private layers;
4243
4499
  add(l: Layer | BaseHandle): void;
4244
- get(id: string): Layer | BaseHandle<BaseDesc<BaseDescConfig, BaseDescConfigUpdate, BaseInstance, BaseEventMap>> | undefined;
4500
+ get(id: string): Layer | BaseHandle< BaseDesc<BaseDescConfig, BaseDescConfigUpdate, BaseInstance, BaseEventMap>> | undefined;
4245
4501
  emitById<K extends keyof LayerEvent>(k: K, id: string, ...args: Parameters<LayerEvent[K]>): void;
4246
4502
  emitAll<K extends keyof LayerEvent>(k: K, ...args: Parameters<LayerEvent[K]>): void;
4247
4503
  getResourceLayers(): Generator<Layer, void, unknown>;
@@ -4703,6 +4959,10 @@ export declare type MemoryStats = {
4703
4959
  gpuBytesEst: number;
4704
4960
  externalCpuBytes: number;
4705
4961
  reservedBytes: number;
4962
+ /** Estimated GPU bytes of fixed screen-sized allocations (the
4963
+ * postprocessing render-target stack), reported via
4964
+ * `Core.setFixedGpuBytes` on init, resize, and pass-list changes. */
4965
+ fixedGpuBytes: number;
4706
4966
  budgetBytes: number | undefined;
4707
4967
  evictedCount: number;
4708
4968
  sseMultiplier: number;
@@ -4726,6 +4986,7 @@ declare class MemoryStats_2 {
4726
4986
  readonly evictedCount: number;
4727
4987
  readonly externalBufferBytes: number;
4728
4988
  readonly externalCpuBytes: number;
4989
+ readonly fixedGpuBytes: number;
4729
4990
  readonly gpuBytesEst: number;
4730
4991
  readonly reservedBytes: number;
4731
4992
  readonly retainedRaster: number;
@@ -5035,7 +5296,7 @@ export declare abstract class MeshDesc<Config extends MeshConfig = MeshConfig, U
5035
5296
  * `this.ctx.registerPickableMesh(this.id, wrapper)` before returning.
5036
5297
  */
5037
5298
  abstract createMesh(): Instance;
5038
- get raw(): (Instance extends Object3D<Object3DEventMap> ? Instance : never) | (Instance extends {
5299
+ get raw(): (Instance extends Object3D< Object3DEventMap> ? Instance : never) | (Instance extends {
5039
5300
  raw: infer Raw extends Object3D;
5040
5301
  } ? Raw : never) | undefined;
5041
5302
  onCreate(): void;
@@ -5688,7 +5949,10 @@ export declare type Options = {
5688
5949
  container?: HTMLElement;
5689
5950
  /** Canvas element for rendering. If not provided, a new canvas is created. */
5690
5951
  canvas?: HTMLCanvasElement | OffscreenCanvas;
5691
- /** Device pixel ratio override. Uses device default if not specified. */
5952
+ /** Device pixel ratio override. When not specified, the device value is
5953
+ * used, capped at 2 on mobile (1 with `mobileOptimization`) — screen-sized
5954
+ * render targets grow quadratically with pixel ratio and dominate mobile
5955
+ * GPU memory. An explicit value bypasses the caps. */
5692
5956
  pixelRatio?: number;
5693
5957
  /** Disables automatic resize handling on window resize events. */
5694
5958
  disableAutoResize?: boolean;
@@ -6090,6 +6354,28 @@ declare class PointMaterial {
6090
6354
  set clampToGround(value: boolean | null | undefined);
6091
6355
  get color(): number | undefined;
6092
6356
  set color(value: number | null | undefined);
6357
+ /**
6358
+ * Placement priority for decluttering; higher wins. Only meaningful when
6359
+ * `declutter` is enabled. Defaults to `0.0`.
6360
+ */
6361
+ get declutterPriority(): number | undefined;
6362
+ /**
6363
+ * Placement priority for decluttering; higher wins. Only meaningful when
6364
+ * `declutter` is enabled. Defaults to `0.0`.
6365
+ */
6366
+ set declutterPriority(value: number | null | undefined);
6367
+ /**
6368
+ * Participate in screen-space decluttering: when labels/sprites overlap
6369
+ * on screen, lower-priority ones are hidden. Defaults to `true`; set to
6370
+ * `false` to draw every label unconditionally.
6371
+ */
6372
+ get declutter(): boolean | undefined;
6373
+ /**
6374
+ * Participate in screen-space decluttering: when labels/sprites overlap
6375
+ * on screen, lower-priority ones are hidden. Defaults to `true`; set to
6376
+ * `false` to draw every label unconditionally.
6377
+ */
6378
+ set declutter(value: boolean | null | undefined);
6093
6379
  get depthTest(): boolean | undefined;
6094
6380
  set depthTest(value: boolean | null | undefined);
6095
6381
  /**
@@ -7327,16 +7613,21 @@ export declare class RenderPass extends RenderPass_2 {
7327
7613
  * Orchestrate rendering passes with ordered management and flexible insertion.
7328
7614
  */
7329
7615
  declare class RenderPassOrchestrator {
7330
- lights: Group<Object3DEventMap>;
7616
+ lights: Group< Object3DEventMap>;
7331
7617
  scenes: {
7332
- mrt: Scene<Object3DEventMap>;
7333
- globe: Scene<Object3DEventMap>;
7334
- draped: Scene<Object3DEventMap>;
7335
- opaque: Scene<Object3DEventMap>;
7336
- transparent: Scene<Object3DEventMap>;
7337
- skyEnvMap: Scene<Object3DEventMap>;
7618
+ mrt: Scene< Object3DEventMap>;
7619
+ globe: Scene< Object3DEventMap>;
7620
+ draped: Scene< Object3DEventMap>;
7621
+ opaque: Scene< Object3DEventMap>;
7622
+ transparent: Scene< Object3DEventMap>;
7623
+ skyEnvMap: Scene< Object3DEventMap>;
7338
7624
  };
7339
7625
  effectComposer: EffectComposer;
7626
+ /**
7627
+ * Invoked whenever the pass list changes (add/insert/remove/clear), so the
7628
+ * owner can re-report the fixed GPU footprint to the memory ledger.
7629
+ */
7630
+ onPassesChanged?: () => void;
7340
7631
  private passMap;
7341
7632
  constructor(renderer: WebGLRenderer, options: RenderPassOrchestratorOptions);
7342
7633
  setSize(width: number, height: number): void;
@@ -7369,6 +7660,12 @@ declare class RenderPassOrchestrator {
7369
7660
  * Clear all passes.
7370
7661
  */
7371
7662
  clearPasses(): void;
7663
+ /**
7664
+ * Estimates the resident GPU bytes of the fixed, screen-sized render-target
7665
+ * stack (composer buffers + every target reachable from the passes), for
7666
+ * reporting into the memory ledger's `fixed_gpu_bytes` term.
7667
+ */
7668
+ estimateFixedGpuBytes(): number;
7372
7669
  /**
7373
7670
  * Dispose all GPU resources held by the effect composer.
7374
7671
  */
@@ -7396,7 +7693,12 @@ export declare class RenderTargetCopyPass extends Pass_2 {
7396
7693
  get autoResize(): boolean;
7397
7694
  set autoResize(value: boolean);
7398
7695
  setTexture(texture: Texture): void;
7399
- setDepthTexture(texture: Texture): void;
7696
+ /**
7697
+ * When a depth texture is set, the pass copies its depth into the target's
7698
+ * depth buffer via gl_FragDepth. Depth test must be enabled (with AlwaysDepth)
7699
+ * because GL discards depth writes while the depth test is disabled.
7700
+ */
7701
+ setDepthTexture(texture: Texture | null): void;
7400
7702
  render(renderer: WebGLRenderer, inputBuffer: WebGLRenderTarget | null, _outputBuffer: WebGLRenderTarget | null): void;
7401
7703
  dispose(): void;
7402
7704
  }
@@ -7525,6 +7827,13 @@ export declare type SdfTextBaseMutates = Mutates<SdfTextBaseState, SdfTextBaseUn
7525
7827
  * Set the batch ID uniform (immutable after mount, but needed for batch creation).
7526
7828
  */
7527
7829
  setBatchId: (batchId: number) => void;
7830
+ /**
7831
+ * Set the declutter hide factor (0 = shown … 1 = hidden); the fragment
7832
+ * shader scales opacity by `1 - value` and the vertex shader hard-culls
7833
+ * at 1. Kept separate from `show`/`opacity` so user-driven visibility and
7834
+ * declutter results compose instead of clobbering each other.
7835
+ */
7836
+ setDeclutterHide: (value: number) => void;
7528
7837
  }>;
7529
7838
 
7530
7839
  /**
@@ -7583,6 +7892,10 @@ declare type SdfTextBaseRefs = {
7583
7892
  uTextWidth: UniformValue<number>;
7584
7893
  uTextHeight: UniformValue<number>;
7585
7894
  uBgYBounds: UniformValue<Vector2>;
7895
+ /** Screen-space declutter hide factor (0 = shown … 1 = hidden), animated
7896
+ * by the declutter fade. Driven by the declutter pass, not by material
7897
+ * style updates. */
7898
+ uDeclutterHide: UniformValue<number>;
7586
7899
  uRTCCenter: UniformValue<Vector3>;
7587
7900
  uRTCCenterView: UniformValue<Vector3>;
7588
7901
  uEyeRTELow: UniformValue<Vector3>;
@@ -7670,6 +7983,26 @@ export declare class SDFTextMesh extends Mesh_2<InstancedBufferGeometry, ShaderM
7670
7983
  private _reprepare?;
7671
7984
  /** Ask the owner to schedule a render after an async re-prepare. */
7672
7985
  private _requestRender?;
7986
+ /** World-space anchor in ECEF meters (f64), kept in sync with the position
7987
+ * uniforms so the declutter pass can project it without touching WASM. */
7988
+ private _worldAnchor;
7989
+ /** Whether this label participates in screen-space decluttering. */
7990
+ private _declutter;
7991
+ /** Layer-level placement priority from the material. */
7992
+ private _declutterPriority;
7993
+ /** Per-feature priority set through the evaluator; overrides the layer
7994
+ * value when defined. */
7995
+ private _declutterPriorityOverride;
7996
+ /** Current animated hide factor (mirrors the uDeclutterHide uniform) and
7997
+ * the placement target it is fading toward. */
7998
+ private _declutterHide;
7999
+ private _declutterTarget;
8000
+ /** Text block dimensions in em units, mirroring the uTextWidth/uTextHeight/
8001
+ * uBgYBounds uniforms; 0 width means "no collision box" (empty text). */
8002
+ private _labelWidthEm;
8003
+ private _labelHeightEm;
8004
+ private _labelMinYEm;
8005
+ private _labelMaxYEm;
7673
8006
  private _enhancer;
7674
8007
  constructor(position: Float32Array | {
7675
8008
  high: Float32Array;
@@ -7716,12 +8049,42 @@ export declare class SDFTextMesh extends Mesh_2<InstancedBufferGeometry, ShaderM
7716
8049
  setHeight(height: number): void;
7717
8050
  setSize(size: number): void;
7718
8051
  setOpacity(opacity: number): void;
8052
+ /**
8053
+ * Set this label's declutter fade target; the actual hide factor animates
8054
+ * toward it in {@link stepDeclutterFade}. Deliberately separate from
8055
+ * `visible`/`show`: it neither churns scene-graph membership nor releases
8056
+ * glyph atlas retains, so the declutter pass can retarget it every
8057
+ * placement run at no cost.
8058
+ */
8059
+ setDeclutterHidden(hidden: boolean): void;
8060
+ /**
8061
+ * Advance the hide factor toward its target by `deltaMs / DECLUTTER_FADE_MS`
8062
+ * and push it to the uniform. Returns true while still mid-fade.
8063
+ */
8064
+ stepDeclutterFade(deltaMs: number): boolean;
7719
8065
  _setFeatureWidth(_width: number): void;
7720
8066
  _setFeatureOpacity(opacity: number): void;
7721
8067
  setPosition(position: Float32Array | {
7722
8068
  high: Float32Array;
7723
8069
  low: Float32Array;
7724
8070
  }, RTE: boolean, transform: Transform_2): void;
8071
+ /** Reconstruct the absolute ECEF anchor from the same inputs the position
8072
+ * uniforms receive (RTE high+low split, or RTC-relative + center). */
8073
+ private _cacheWorldAnchor;
8074
+ /**
8075
+ * Build this label's collision candidate for the shared declutter pass, or
8076
+ * null when it doesn't participate (declutter disabled, hidden, or empty).
8077
+ * The local box mirrors the vertex shader's layout: glyphs span
8078
+ * [0, textWidth] × [bgMinY, bgMaxY] in em units, shifted by the `center`
8079
+ * anchor and scaled by the font size (sdfText.vert.glsl:111-115).
8080
+ */
8081
+ getDeclutterCandidate(owner: DeclutterParticipant, handle: number): DeclutterCandidate | null;
8082
+ /**
8083
+ * Set a per-feature placement priority (higher wins), overriding the
8084
+ * layer-level `declutterPriority` for this label. Pass `undefined` to fall
8085
+ * back to the layer value. Driven by the feature evaluator.
8086
+ */
8087
+ setDeclutterPriority(priority: number | undefined): void;
7725
8088
  /**
7726
8089
  * Apply material properties from WASM TextMaterial.
7727
8090
  * Maps relevant properties to enhancer updates, with change tracking.
@@ -8322,6 +8685,28 @@ declare class TextMaterial {
8322
8685
  set clampToGround(value: boolean | null | undefined);
8323
8686
  get color(): number | undefined;
8324
8687
  set color(value: number | null | undefined);
8688
+ /**
8689
+ * Placement priority for decluttering; higher wins. Only meaningful when
8690
+ * `declutter` is enabled. Defaults to `0.0`.
8691
+ */
8692
+ get declutterPriority(): number | undefined;
8693
+ /**
8694
+ * Placement priority for decluttering; higher wins. Only meaningful when
8695
+ * `declutter` is enabled. Defaults to `0.0`.
8696
+ */
8697
+ set declutterPriority(value: number | null | undefined);
8698
+ /**
8699
+ * Participate in screen-space decluttering: when labels/sprites overlap
8700
+ * on screen, lower-priority ones are hidden. Defaults to `true`; set to
8701
+ * `false` to draw every label unconditionally.
8702
+ */
8703
+ get declutter(): boolean | undefined;
8704
+ /**
8705
+ * Participate in screen-space decluttering: when labels/sprites overlap
8706
+ * on screen, lower-priority ones are hidden. Defaults to `true`; set to
8707
+ * `false` to draw every label unconditionally.
8708
+ */
8709
+ set declutter(value: boolean | null | undefined);
8325
8710
  get depthTest(): boolean | undefined;
8326
8711
  set depthTest(value: boolean | null | undefined);
8327
8712
  /**
@@ -8591,6 +8976,14 @@ declare class ThreeView<D extends Descriptions = EmptyDescriptions> extends Even
8591
8976
  private _eventDisposer;
8592
8977
  private _disposed;
8593
8978
  private _renderFlag;
8979
+ /** Shared screen-space label declutterer for text/sprite features. */
8980
+ private _declutter;
8981
+ /** Reusable Vector2 for the declutter pass's per-frame viewport query. */
8982
+ private _declutterSize;
8983
+ /** Pending follow-up frame for a throttled declutter pass or an active
8984
+ * fade, with the delay it was scheduled at (so a shorter need preempts). */
8985
+ private _declutterRetry;
8986
+ private _declutterRetryDelay;
8594
8987
  private _isIdle;
8595
8988
  private _uniforms;
8596
8989
  private _meshes;
@@ -8636,6 +9029,10 @@ declare class ThreeView<D extends Descriptions = EmptyDescriptions> extends Even
8636
9029
  /** Built-in attribution UI; unset when disabled or in a worker (no DOM). */
8637
9030
  private _attribution?;
8638
9031
  private pixelRatioMatchedMedia?;
9032
+ private fixedGpuBytesReportScheduled;
9033
+ private fixedGpuBytesResyncPending;
9034
+ private framesSinceFixedGpuBytesReport;
9035
+ private lastReportedFixedGpuBytes;
8639
9036
  /**
8640
9037
  * The built-in attribution (credit) UI. `undefined` when disabled via
8641
9038
  * `defaultAttribution: false`, or in a worker / no-DOM environment. Feed it
@@ -8745,6 +9142,19 @@ declare class ThreeView<D extends Descriptions = EmptyDescriptions> extends Even
8745
9142
  * @param pixelRatio - Device pixel ratio
8746
9143
  */
8747
9144
  resize: (width?: number, height?: number, pixelRatio?: number) => void;
9145
+ /**
9146
+ * Walks the fixed render-target stack and pushes the estimate into the
9147
+ * memory ledger; the WASM call is skipped while the value is unchanged.
9148
+ */
9149
+ private _reportFixedGpuBytes;
9150
+ /**
9151
+ * Re-reports the fixed GPU footprint for event-triggered changes (init,
9152
+ * resize, pass add/remove). Scheduled as a microtask so bursts — e.g.
9153
+ * effect setup during init — coalesce into a single walk, and marks a
9154
+ * one-shot post-render resync because these events run before the GPU has
9155
+ * lazily allocated the affected targets.
9156
+ */
9157
+ private _scheduleFixedGpuBytesReport;
8748
9158
  private _updateUniforms;
8749
9159
  /** Returns true if the scene was updated and needs to be rendered. */
8750
9160
  private _update;
@@ -8753,6 +9163,14 @@ declare class ThreeView<D extends Descriptions = EmptyDescriptions> extends Even
8753
9163
  * This is called after the main update loop to batch feature updates
8754
9164
  */
8755
9165
  private _forceFeatureUpdates;
9166
+ /**
9167
+ * Ask for a future frame on behalf of the declutter pass. Runs through a
9168
+ * timer because the main loop clears `forceUpdate` right after `_render` —
9169
+ * a flag set synchronously here would be wiped before the next tick reads
9170
+ * it. A pending longer timer is preempted when a shorter delay is needed
9171
+ * (a fade must not wait out a throttle window).
9172
+ */
9173
+ private _scheduleDeclutterFrame;
8756
9174
  private _render;
8757
9175
  /**
8758
9176
  * Since passing Color class to WASM is tricky, converts Navara Color
@@ -9136,6 +9554,12 @@ declare type TileHandler = {
9136
9554
  * subdivision past the vector `maxZoom`. Pass 0 to release on dispose. */
9137
9555
  reportDrapeGpuBytes: (handle: bigint, bytes: number) => void;
9138
9556
  calcMetersPerTexel: (tileHandle: bigint, textureZoom: number, textureWidth: number) => number;
9557
+ /** Rust's clamped WebMercator northing (`navara_geometry::mercator_y`).
9558
+ * The composite paste derives its per-slot reprojection constants through
9559
+ * this so paste and bake (`uv_rect_from_extents_mercator`) share one
9560
+ * implementation — a drifting reimplementation misaligns the pasted
9561
+ * latitude band (and NaNs on the unclamped polar band). */
9562
+ mercatorY: (lat: number) => number;
9139
9563
  };
9140
9564
 
9141
9565
  declare class TileLayerDescription {
@@ -9200,7 +9624,7 @@ export declare class TileMesh extends Mesh_2<BufferGeometry, TileMaterial, Custo
9200
9624
  private buildCompositeLayers;
9201
9625
  _init(mesh: MeshAdded): Promise<void>;
9202
9626
  private createMesh;
9203
- createSkirtMesh(mesh: Mesh, terrainGeometry: BufferGeometry, position: Float32Array, uv: Float32Array | null, indices: Uint32Array, normals: Float32Array | null): BufferGeometry<NormalBufferAttributes, BufferGeometryEventMap>;
9627
+ createSkirtMesh(mesh: Mesh, terrainGeometry: BufferGeometry, position: Float32Array, uv: Float32Array | null, indices: Uint32Array, normals: Float32Array | null): BufferGeometry< NormalBufferAttributes, BufferGeometryEventMap>;
9204
9628
  private shouldUseNormal;
9205
9629
  private initMaterial;
9206
9630
  _update(mesh: MeshChanged): void;
@@ -9392,6 +9816,7 @@ declare class TileTextureCompositor {
9392
9816
  * per-tile GPU byte cost it reports to the memory ledger. */
9393
9817
  readonly size: number;
9394
9818
  private readonly texturizedScenes;
9819
+ private readonly mercatorY;
9395
9820
  private readonly bakeCamera;
9396
9821
  private readonly quadScene;
9397
9822
  private readonly quadCamera;
@@ -9502,6 +9927,10 @@ declare class TileTextureCompositor {
9502
9927
  declare type TileTextureCompositorOptions = {
9503
9928
  renderer: WebGLRenderer;
9504
9929
  texturizedSceneByTileCoordinates: TexturizedSceneByTileCoordinates;
9930
+ /** Rust's clamped WebMercator northing (`TileHandler.mercatorY`), handed to
9931
+ * the core uniform mutates so the paste-side reprojection constants come
9932
+ * from the same implementation as the Rust bake affine. */
9933
+ mercatorY: (lat: number) => number;
9505
9934
  /** Atlas RT side length (defaults to 512). */
9506
9935
  size?: number;
9507
9936
  /** Test seam: replace MRT RT creation. */
@@ -9727,7 +10156,7 @@ export declare type TransparentPassConfig = Description_4 & EffectConfig;
9727
10156
  export declare class TransparentPassEffectDesc extends EffectDesc<TransparentPassConfig, TransparentPassUpdate, RenderPass> {
9728
10157
  static key: string;
9729
10158
  static insertAfter: string[];
9730
- light: Group<Object3DEventMap>;
10159
+ light: Group< Object3DEventMap>;
9731
10160
  lightsSyncMap: Map<any, any>;
9732
10161
  createPass(): RenderPass;
9733
10162
  update(_time: number): void;