incanto 0.22.0 → 0.24.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.
package/dist/2d.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
2
- import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-B-M1zune.js";
2
+ import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-DrcEgRup.js";
3
3
  import { _ as RigidBody2D, a as parseCells, c as ColorRect2D, d as AnimatedSprite2D, f as Sprite2D, g as PhysicsBody2D, h as CharacterBody2D, i as mergeSolidRects, l as CharacterController2D, m as Area2D, n as UILayer, o as Particles2D, p as Joint2D, r as TileMap2D, s as Label, t as registerNodes2D, u as Camera2D, v as StaticBody2D, y as Node2D } from "./register-CvpSUU3O.js";
4
4
  import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-DiVFFlH3.js";
5
5
  //#region src/2d/library-sprite.ts
package/dist/3d.d.ts CHANGED
@@ -377,6 +377,9 @@ interface CreateGame3DOptions {
377
377
  seed?: number;
378
378
  fixedHz?: number;
379
379
  pixelRatio?: number;
380
+ /** Keep the frame rate by rendering fewer pixels while frames run slow
381
+ * (default ON). `false` pins the resolution — screenshots, capture, tests. */
382
+ adaptiveResolution?: boolean;
380
383
  resolveScene?: LoadSceneOptions["resolveScene"];
381
384
  /** @internal Test seam — replaces the Renderer3D construction. */
382
385
  _rendererFactory?: (engine: Engine, canvas: HTMLCanvasElement) => GameRenderer;
@@ -2285,6 +2288,12 @@ declare class Water3D extends Node3D implements RenderHook3D, SunConsumer3D {
2285
2288
  * render per frame, so it is off by default; a still lake earns it.
2286
2289
  */
2287
2290
  mirror: boolean;
2291
+ /**
2292
+ * Milliseconds between planar-mirror re-renders. A reflection seen through a
2293
+ * rippling surface does not need 60 Hz — 33 ms halves the pass's cost and
2294
+ * nobody can tell. 0 re-renders every frame.
2295
+ */
2296
+ mirrorInterval: number;
2288
2297
  /** ms between reflection (and foam depth) re-renders. */
2289
2298
  reflectionInterval: number;
2290
2299
  /** Depth-texture shoreline foam — rides the always-on fancy scene pass. */
@@ -2378,6 +2387,8 @@ declare class Water3D extends Node3D implements RenderHook3D, SunConsumer3D {
2378
2387
  private readonly _scratchA;
2379
2388
  private readonly _scratchB;
2380
2389
  private readonly _bodies;
2390
+ /** Scratch for the side-pass cull (no per-frame allocation). */
2391
+ private readonly _passHidden;
2381
2392
  private cubeTarget;
2382
2393
  private cubeCamera;
2383
2394
  /** Reflection near plane (max half extent) — recreate the camera on resize. */
@@ -2388,6 +2399,7 @@ declare class Water3D extends Node3D implements RenderHook3D, SunConsumer3D {
2388
2399
  private mirrorTarget;
2389
2400
  private readonly mirrorCamera;
2390
2401
  private readonly mirrorMatrix;
2402
+ private lastMirrorAt;
2391
2403
  protected override _createObject3D(): Object3D;
2392
2404
  override update(dt: number): void;
2393
2405
  override _syncObject3D(): void;
@@ -2457,6 +2469,14 @@ interface Renderer3DOptions {
2457
2469
  assets?: AssetStore3D;
2458
2470
  /** Defaults to `window.devicePixelRatio` capped at 2. */
2459
2471
  pixelRatio?: number;
2472
+ /**
2473
+ * Keep the frame rate by rendering at fewer pixels when frames run slow, and
2474
+ * hand them back when they recover (default ON). A retina display asks for
2475
+ * 4× the pixels; shaded water is fragment-heavy; the honest answer is fewer
2476
+ * pixels of the same world, only while it is actually needed. `false` pins
2477
+ * the resolution — for screenshots, video capture and pixel-diff tests.
2478
+ */
2479
+ adaptiveResolution?: boolean;
2460
2480
  }
2461
2481
  /**
2462
2482
  * WebGL presentation layer: subscribes to `engine.updated`, mirrors the active
@@ -2524,10 +2544,22 @@ declare class Renderer3D {
2524
2544
  private bloomCompositeScene;
2525
2545
  private bloomCompositeUniforms;
2526
2546
  constructor(opts: Renderer3DOptions);
2547
+ /** The pixel ratio the scene ASKED for — the governor scales this, never replaces it. */
2548
+ private readonly basePixelRatio;
2549
+ private readonly adaptive;
2550
+ private lastFrameAt;
2527
2551
  private readonly debugLines;
2528
2552
  private readonly selectionLines;
2529
2553
  private syncSelectionOutline;
2530
2554
  private syncDebugLines;
2555
+ /**
2556
+ * Frame-rate governor: measure the frame, and when the median of a window is
2557
+ * slow, render the same world at fewer pixels (and hand them back when it
2558
+ * recovers). Resizing the drawing buffer is all it takes — every render
2559
+ * target in the pipeline is keyed off `getDrawingBufferSize`, so the water
2560
+ * grab, the mirror and the bloom chain follow automatically.
2561
+ */
2562
+ private governResolution;
2531
2563
  private render;
2532
2564
  /**
2533
2565
  * Bloom post pass (only when `environment.bloom` is declared). LDR and safe:
package/dist/3d.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
2
- import { A as Water3D, F as StaticBody3D, I as Node3D, M as CharacterBody3D, N as PhysicsBody3D, P as RigidBody3D, j as Area3D, z as WATER_MAX_RIPPLES } from "./gameplay-Dib5mNFD.js";
3
- import { a as Environment3D, c as sunDirectionFromElevationAzimuth, i as syncTree, l as sunDirectionFromSky, o as horizonColorFromSky, r as Renderer3D, s as parseEnvironment3D, t as createGame3D, u as AssetStore3D } from "./create-game-C3uiw80V.js";
4
- import { A as QUARTER_PITCH, C as BoneAttachment3D, D as TERRAIN_THEMES, E as DEFAULT_TERRAIN_TEXTURE_BASE, M as keyboardIntensity, N as movementState, O as terrainThemeLayers, P as rigPose, S as BoneLookAt3D, T as Terrain3D, _ as Flowers3D, a as Trail3D, b as CharacterController3D, c as Particles3D, d as DirectionalLight3D, f as OmniLight3D, g as DENSITY_PRESETS, h as Foliage3D, i as Tree3D, j as cameraRelative, k as Joint3D, l as ModelInstance3D, m as MeshInstance3D, n as VOXEL_PALETTE, o as River3D, p as InstancedMesh3D, r as VoxelGrid3D, s as traceDownhillPath, t as registerNodes3D, u as LoftMesh3D, v as resolveFlowerDensity, w as Billboard3D, x as Camera3D, y as FLOWER_VARIETIES } from "./register-CHgVdSbp.js";
2
+ import { A as Water3D, F as StaticBody3D, I as Node3D, M as CharacterBody3D, N as PhysicsBody3D, P as RigidBody3D, j as Area3D, z as WATER_MAX_RIPPLES } from "./gameplay-BJ5gXIks.js";
3
+ import { a as Environment3D, c as sunDirectionFromElevationAzimuth, i as syncTree, l as sunDirectionFromSky, o as horizonColorFromSky, r as Renderer3D, s as parseEnvironment3D, t as createGame3D, u as AssetStore3D } from "./create-game-DjWIgtQ_.js";
4
+ import { A as QUARTER_PITCH, C as BoneAttachment3D, D as TERRAIN_THEMES, E as DEFAULT_TERRAIN_TEXTURE_BASE, M as keyboardIntensity, N as movementState, O as terrainThemeLayers, P as rigPose, S as BoneLookAt3D, T as Terrain3D, _ as Flowers3D, a as Trail3D, b as CharacterController3D, c as Particles3D, d as DirectionalLight3D, f as OmniLight3D, g as DENSITY_PRESETS, h as Foliage3D, i as Tree3D, j as cameraRelative, k as Joint3D, l as ModelInstance3D, m as MeshInstance3D, n as VOXEL_PALETTE, o as River3D, p as InstancedMesh3D, r as VoxelGrid3D, s as traceDownhillPath, t as registerNodes3D, u as LoftMesh3D, v as resolveFlowerDensity, w as Billboard3D, x as Camera3D, y as FLOWER_VARIETIES } from "./register-CpJORtm4.js";
5
5
  import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
6
- import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-DLPPRNu4.js";
6
+ import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-CpIB9C-F.js";
7
7
  //#region src/3d/environment-runtime.ts
8
8
  /**
9
9
  * Live environment editing — the renderer re-applies `scene.environment`
@@ -3,10 +3,10 @@ import { _ as registerBehavior, n as loadScene } from "./loader-BZqOKfI2.js";
3
3
  import { l as AudioPlayer, u as Engine } from "./register-nObreUQR.js";
4
4
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
5
5
  import { i as resolveRendering, n as attachTouchControls } from "./touch-031PxtCR.js";
6
- import { I as Node3D, N as PhysicsBody3D, R as createCausticsQuad, n as registerGameplayBehaviors } from "./gameplay-Dib5mNFD.js";
6
+ import { I as Node3D, N as PhysicsBody3D, R as createCausticsQuad, n as registerGameplayBehaviors } from "./gameplay-BJ5gXIks.js";
7
7
  import { t as debugSources } from "./debug-draw-CZmOYjL2.js";
8
- import { d as DirectionalLight3D, l as ModelInstance3D, t as registerNodes3D, x as Camera3D } from "./register-CHgVdSbp.js";
9
- import { n as enablePhysics3D } from "./physics-3d-DLPPRNu4.js";
8
+ import { d as DirectionalLight3D, l as ModelInstance3D, t as registerNodes3D, x as Camera3D } from "./register-CpJORtm4.js";
9
+ import { n as enablePhysics3D } from "./physics-3d-CpIB9C-F.js";
10
10
  import { ACESFilmicToneMapping, AmbientLight, Box3, BufferAttribute, BufferGeometry, Color, DepthTexture, EquirectangularReflectionMapping, FloatType, Fog, HalfFloatType, LineBasicMaterial, LineSegments, Matrix4, Mesh, PCFShadowMap, PMREMGenerator, PerspectiveCamera, PlaneGeometry, Quaternion, Raycaster, Scene, ShaderMaterial, Vector2, Vector3, WebGLRenderTarget, WebGLRenderer } from "three";
11
11
  import { VRMLoaderPlugin, VRMUtils } from "@pixiv/three-vrm";
12
12
  import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
@@ -126,6 +126,50 @@ var AssetStore3D = class {
126
126
  }
127
127
  };
128
128
  //#endregion
129
+ //#region src/3d/adaptive-resolution.ts
130
+ const DEFAULTS = {
131
+ slowMs: 20,
132
+ fastMs: 13,
133
+ minScale: .6,
134
+ step: .15,
135
+ window: 45
136
+ };
137
+ var AdaptiveResolution = class {
138
+ opts;
139
+ samples = [];
140
+ scale = 1;
141
+ constructor(options = {}) {
142
+ this.opts = {
143
+ ...DEFAULTS,
144
+ ...options
145
+ };
146
+ }
147
+ /** The fraction of the requested pixel ratio to render at right now. */
148
+ current() {
149
+ return this.scale;
150
+ }
151
+ /**
152
+ * Feed one frame's duration. Returns the new scale when it CHANGED (the
153
+ * caller then resizes), else null — so a steady frame rate costs nothing.
154
+ */
155
+ push(frameMs) {
156
+ if (!(frameMs > 0) || !Number.isFinite(frameMs)) return null;
157
+ this.samples.push(frameMs);
158
+ if (this.samples.length < this.opts.window) return null;
159
+ const sorted = [...this.samples].sort((a, b) => a - b);
160
+ const median = sorted[Math.floor(sorted.length / 2)];
161
+ this.samples = [];
162
+ const before = this.scale;
163
+ if (median > this.opts.slowMs) this.scale = Math.max(this.opts.minScale, this.scale - this.opts.step);
164
+ else if (median < this.opts.fastMs && this.scale < 1) this.scale = Math.min(1, this.scale + this.opts.step);
165
+ return this.scale === before ? null : this.scale;
166
+ }
167
+ /** Forget the window (a paused or backgrounded game is not "slow"). */
168
+ reset() {
169
+ this.samples = [];
170
+ }
171
+ };
172
+ //#endregion
129
173
  //#region src/3d/bloom/bloom-composite.ts
130
174
  /**
131
175
  * HDR bloom post pass:
@@ -1421,7 +1465,9 @@ var Renderer3D = class {
1421
1465
  canvas: opts.canvas,
1422
1466
  antialias: rendering.antialias
1423
1467
  });
1468
+ this.basePixelRatio = rendering.pixelRatio;
1424
1469
  this.webgl.setPixelRatio(rendering.pixelRatio);
1470
+ this.adaptive = opts.adaptiveResolution === false ? null : new AdaptiveResolution();
1425
1471
  this.webgl.shadowMap.enabled = true;
1426
1472
  this.webgl.shadowMap.type = PCFShadowMap;
1427
1473
  this.webgl.toneMapping = ACESFilmicToneMapping;
@@ -1445,6 +1491,10 @@ var Renderer3D = class {
1445
1491
  this.threeScene.add(this.selectionLines);
1446
1492
  this.disconnect = this.engine.updated.connect(() => this.render());
1447
1493
  }
1494
+ /** The pixel ratio the scene ASKED for — the governor scales this, never replaces it. */
1495
+ basePixelRatio;
1496
+ adaptive;
1497
+ lastFrameAt = 0;
1448
1498
  debugLines;
1449
1499
  selectionLines;
1450
1500
  syncSelectionOutline() {
@@ -1468,9 +1518,35 @@ var Renderer3D = class {
1468
1518
  this.debugLines.visible = vertices !== null;
1469
1519
  if (vertices) this.debugLines.geometry.setAttribute("position", new BufferAttribute(vertices, 3));
1470
1520
  }
1521
+ /**
1522
+ * Frame-rate governor: measure the frame, and when the median of a window is
1523
+ * slow, render the same world at fewer pixels (and hand them back when it
1524
+ * recovers). Resizing the drawing buffer is all it takes — every render
1525
+ * target in the pipeline is keyed off `getDrawingBufferSize`, so the water
1526
+ * grab, the mirror and the bloom chain follow automatically.
1527
+ */
1528
+ governResolution() {
1529
+ const gov = this.adaptive;
1530
+ if (!gov) return;
1531
+ const now = globalThis.performance?.now?.() ?? 0;
1532
+ const prev = this.lastFrameAt;
1533
+ this.lastFrameAt = now;
1534
+ if (prev === 0) return;
1535
+ const frameMs = now - prev;
1536
+ if (frameMs > 500) {
1537
+ gov.reset();
1538
+ return;
1539
+ }
1540
+ const scale = gov.push(frameMs);
1541
+ if (scale === null) return;
1542
+ this.webgl.setPixelRatio(this.basePixelRatio * scale);
1543
+ const size = this.lastSize;
1544
+ if (size.w > 0 && size.h > 0) this.webgl.setSize(size.w, size.h, false);
1545
+ }
1471
1546
  render() {
1472
1547
  const scene = this.engine.scene;
1473
1548
  if (!scene) return;
1549
+ this.governResolution();
1474
1550
  this.syncDebugLines();
1475
1551
  this.syncSelectionOutline();
1476
1552
  if (scene.assets && !this.loadedAssetScenes.has(scene)) {
@@ -1937,7 +2013,8 @@ async function createGame3D(opts) {
1937
2013
  const renderer = opts._rendererFactory ? opts._rendererFactory(engine, opts.canvas) : new Renderer3D({
1938
2014
  canvas: opts.canvas,
1939
2015
  engine,
1940
- ...opts.pixelRatio !== void 0 ? { pixelRatio: opts.pixelRatio } : {}
2016
+ ...opts.pixelRatio !== void 0 ? { pixelRatio: opts.pixelRatio } : {},
2017
+ ...opts.adaptiveResolution !== void 0 ? { adaptiveResolution: opts.adaptiveResolution } : {}
1941
2018
  });
1942
2019
  if (opts.debug ?? false) {
1943
2020
  const host = opts.touchContainer ?? opts.canvas.parentElement ?? (typeof document !== "undefined" ? document.body : null);
@@ -3,7 +3,7 @@ import { _ as registerBehavior, n as loadScene, o as computeViewport, s as resol
3
3
  import { l as AudioPlayer, u as Engine } from "./register-nObreUQR.js";
4
4
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
5
5
  import { i as resolveRendering, n as attachTouchControls } from "./touch-031PxtCR.js";
6
- import { n as registerGameplayBehaviors } from "./gameplay-Dib5mNFD.js";
6
+ import { n as registerGameplayBehaviors } from "./gameplay-BJ5gXIks.js";
7
7
  import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-CvpSUU3O.js";
8
8
  import { t as debugSources } from "./debug-draw-CZmOYjL2.js";
9
9
  import { n as enablePhysics2D } from "./physics-2d-DiVFFlH3.js";
@@ -398,6 +398,55 @@ void main() {
398
398
  }
399
399
  `;
400
400
  //#endregion
401
+ //#region src/3d/water/pass-cull.ts
402
+ /**
403
+ * What a water side-pass is allowed to skip.
404
+ *
405
+ * Water costs extra SCENE RENDERS — the refraction/depth grab, the planar
406
+ * mirror — and each one re-submits the whole world. On a meadow lake the world
407
+ * is mostly GRASS: tens of thousands of blade triangles that contribute
408
+ * nothing a player can name in a reflection or a depth mask, and everything to
409
+ * the frame budget. These node types are therefore dropped from the side
410
+ * passes; the main render is untouched, so nothing disappears from the scene
411
+ * the player is actually looking at.
412
+ *
413
+ * Foliage/flowers additionally BELONG out of the depth pass: alpha-cutout
414
+ * quads depth-write their full rectangle and wind-displaced blades render
415
+ * unposed, so their depth was always a lie the foam mask had to survive.
416
+ */
417
+ const SKIPPED_IN_WATER_PASSES = new Set([
418
+ "Foliage3D",
419
+ "Flowers3D",
420
+ "Particles3D",
421
+ "Trail3D"
422
+ ]);
423
+ /**
424
+ * Hide the auxiliary nodes for one pass. Returns the objects that were hidden
425
+ * so the caller can restore them — pass the array to {@link restoreForPass}.
426
+ * Allocation-free in the common case: the caller owns the scratch array.
427
+ */
428
+ function hideForWaterPass(root, out) {
429
+ out.length = 0;
430
+ if (typeof root?.traverse !== "function") return out;
431
+ root.traverse((obj) => {
432
+ if (!obj.visible) return;
433
+ const type = (obj.userData?.incantoNode)?.constructor?.typeName;
434
+ if (type && SKIPPED_IN_WATER_PASSES.has(type)) {
435
+ obj.visible = false;
436
+ out.push(obj);
437
+ }
438
+ });
439
+ return out;
440
+ }
441
+ /** Undo {@link hideForWaterPass}. */
442
+ function restoreForWaterPass(hidden) {
443
+ for (let i = 0; i < hidden.length; i++) {
444
+ const obj = hidden[i];
445
+ if (obj) obj.visible = true;
446
+ }
447
+ hidden.length = 0;
448
+ }
449
+ //#endregion
401
450
  //#region src/3d/water/caustics.ts
402
451
  /**
403
452
  * Underwater caustics — the dancing refracted-light pattern the water surface
@@ -1696,8 +1745,26 @@ void main() {
1696
1745
  foamOpacity = max(foamOpacity, mix(baseOpacity, min(baseOpacity + 0.3, 1.0), splashFoam));
1697
1746
  }
1698
1747
 
1748
+ // ── the waterline ───────────────────────────────────────────────────────
1749
+ // Water does not END; it runs out. Without this the surface stays fully
1750
+ // opaque right up to the geometric intersection and the shore reads as a
1751
+ // sheet of vinyl laid on the sand — the single most common tell of game
1752
+ // water. Fade over the last ~18 cm of VERTICAL column (not view depth: at a
1753
+ // grazing angle the view ray is metres long in ankle-deep water), so the
1754
+ // last hand's breadth of wash dissolves into wet ground. Independent of the
1755
+ // foam toggle — a beach without foam still has a waterline.
1756
+ float shoreDissolve = 1.0;
1757
+ if (uUseSceneDepth > 0.5 && waterViewDepth >= 0.0) {
1758
+ float shoreT = camDist * (linearSceneDepth / max(linearWaterDepth, 1e-4));
1759
+ float bedY = cameraPosition.y + viewDirection.y * shoreT;
1760
+ float column = max(uWaterCenter.y - bedY, 0.0);
1761
+ // ragged, so the dissolve edge is a wash line and not a contour
1762
+ float lacy = noise(vWorldPosition.xz * 1.9) * 0.4 + noise(vWorldPosition.xz * 5.3) * 0.2;
1763
+ shoreDissolve = smoothstep(0.0, 0.18 + lacy * 0.12, column);
1764
+ }
1765
+
1699
1766
  // 🔥 Final fundamental solution: Apply depth mask
1700
- float finalOpacity = foamOpacity * depthMask;
1767
+ float finalOpacity = foamOpacity * depthMask * shoreDissolve;
1701
1768
 
1702
1769
  // ── seen from BELOW ─────────────────────────────────────────────────────
1703
1770
  // The underside of water is not the top with the colours swapped. Light can
@@ -2371,8 +2438,14 @@ const WAVE_WORLD_REF = 128;
2371
2438
  const AMPLITUDE_PER_WAVE_HEIGHT = REFERENCE_AMPLITUDE / REFERENCE_WAVE_HEIGHT;
2372
2439
  /** Cube-map reflection resolution (source: reflectionQuality = 256). */
2373
2440
  const REFLECTION_RESOLUTION = 256;
2374
- /** Planar-mirror target size cap (per side) half the drawing buffer, clamped. */
2375
- const MIRROR_PASS_MAX = 1024;
2441
+ /** Cube-map refresh floor while a planar mirror is on it is only the
2442
+ * off-screen fallback then, so six faces a second is already generous. */
2443
+ const MIRRORED_CUBE_INTERVAL = 2e3;
2444
+ /** Planar-mirror target: a THIRD of the drawing buffer, capped. A mirror is
2445
+ * seen through a rippled surface — the resolution nobody can tell apart from
2446
+ * full-res is far lower than the resolution that costs a frame. */
2447
+ const MIRROR_PASS_SCALE = 3;
2448
+ const MIRROR_PASS_MAX = 640;
2376
2449
  /** How far a wavelet's tilt slides the mirror sample, in UV per unit of normal lean. */
2377
2450
  const MIRROR_DISTORT = .06;
2378
2451
  /** Scene pre-pass (depth for absorption/foam + color grab for refraction):
@@ -2389,9 +2462,9 @@ const SCENE_PASS_MAX = 1024;
2389
2462
  const WATERLINE_CLIP_SLACK = .02;
2390
2463
  /** Fancy vertex density: the FBM displaces per vertex, so density scales with
2391
2464
  * extent (the source's formula degenerated to always-256; ours ramps to it). */
2392
- const FANCY_SEGMENTS_PER_M = 4;
2393
- const FANCY_SEGMENTS_MIN = 32;
2394
- const FANCY_SEGMENTS_MAX = 256;
2465
+ const FANCY_SEGMENTS_PER_M = 1.5;
2466
+ const FANCY_SEGMENTS_MIN = 24;
2467
+ const FANCY_SEGMENTS_MAX = 160;
2395
2468
  /** Simple quality: coarse enough to animate every vertex on the CPU. */
2396
2469
  const SIMPLE_SEGMENTS = 32;
2397
2470
  /** Bodies must rise this far above the waterline to 'exit' (no surface flicker). */
@@ -2461,6 +2534,7 @@ var Water3D = class Water3D extends Node3D {
2461
2534
  reflection: { default: true },
2462
2535
  reflectionInterval: { default: 1e3 },
2463
2536
  mirror: { default: false },
2537
+ mirrorInterval: { default: 33 },
2464
2538
  swellSteepness: { default: .35 },
2465
2539
  foam: { default: true },
2466
2540
  interaction: { default: true },
@@ -2512,6 +2586,12 @@ var Water3D = class Water3D extends Node3D {
2512
2586
  * render per frame, so it is off by default; a still lake earns it.
2513
2587
  */
2514
2588
  mirror = false;
2589
+ /**
2590
+ * Milliseconds between planar-mirror re-renders. A reflection seen through a
2591
+ * rippling surface does not need 60 Hz — 33 ms halves the pass's cost and
2592
+ * nobody can tell. 0 re-renders every frame.
2593
+ */
2594
+ mirrorInterval = 33;
2515
2595
  /** ms between reflection (and foam depth) re-renders. */
2516
2596
  reflectionInterval = 1e3;
2517
2597
  /** Depth-texture shoreline foam — rides the always-on fancy scene pass. */
@@ -2671,6 +2751,8 @@ var Water3D = class Water3D extends Node3D {
2671
2751
  z: 0
2672
2752
  };
2673
2753
  _bodies = [];
2754
+ /** Scratch for the side-pass cull (no per-frame allocation). */
2755
+ _passHidden = [];
2674
2756
  cubeTarget = null;
2675
2757
  cubeCamera = null;
2676
2758
  /** Reflection near plane (max half extent) — recreate the camera on resize. */
@@ -2681,6 +2763,7 @@ var Water3D = class Water3D extends Node3D {
2681
2763
  mirrorTarget = null;
2682
2764
  mirrorCamera = new PerspectiveCamera();
2683
2765
  mirrorMatrix = new Matrix4();
2766
+ lastMirrorAt = 0;
2684
2767
  _createObject3D() {
2685
2768
  return new Mesh();
2686
2769
  }
@@ -2736,7 +2819,8 @@ var Water3D = class Water3D extends Node3D {
2736
2819
  this.cubeCamera = new CubeCamera(near, 1e3, this.cubeTarget);
2737
2820
  this.lastReflectionAt = 0;
2738
2821
  }
2739
- if (this.lastReflectionAt === 0 || now - this.lastReflectionAt >= this.rp("reflectionInterval")) {
2822
+ const cubeInterval = this.mirror ? Math.max(this.rp("reflectionInterval"), MIRRORED_CUBE_INTERVAL) : this.rp("reflectionInterval");
2823
+ if (this.lastReflectionAt === 0 || now - this.lastReflectionAt >= cubeInterval) {
2740
2824
  this.lastReflectionAt = now;
2741
2825
  const center = worldTranslationOf(this);
2742
2826
  const cam = this.cubeCamera;
@@ -2753,8 +2837,8 @@ var Water3D = class Water3D extends Node3D {
2753
2837
  }
2754
2838
  if (this.mirror && u.uMirrorMap && u.uMirrorMatrix && u.uUseMirror) {
2755
2839
  ctx.gl.getDrawingBufferSize(drawingBufferScratch);
2756
- const mirrorW = Math.max(1, Math.min(Math.round(drawingBufferScratch.x / 2), MIRROR_PASS_MAX));
2757
- const mirrorH = Math.max(1, Math.min(Math.round(drawingBufferScratch.y / 2), MIRROR_PASS_MAX));
2840
+ const mirrorW = Math.max(1, Math.min(Math.round(drawingBufferScratch.x / MIRROR_PASS_SCALE), MIRROR_PASS_MAX));
2841
+ const mirrorH = Math.max(1, Math.min(Math.round(drawingBufferScratch.y / MIRROR_PASS_SCALE), MIRROR_PASS_MAX));
2758
2842
  if (this.mirrorTarget && (this.mirrorTarget.width !== mirrorW || this.mirrorTarget.height !== mirrorH)) {
2759
2843
  this.mirrorTarget.dispose();
2760
2844
  this.mirrorTarget = null;
@@ -2786,18 +2870,23 @@ var Water3D = class Water3D extends Node3D {
2786
2870
  this.mirrorMatrix.set(.5, 0, 0, .5, 0, .5, 0, .5, 0, 0, .5, .5, 0, 0, 0, 1);
2787
2871
  this.mirrorMatrix.multiply(mirrorCam.projectionMatrix);
2788
2872
  this.mirrorMatrix.multiply(mirrorCam.matrixWorldInverse);
2789
- const prevMirrorTarget = ctx.gl.getRenderTarget();
2790
- const prevMirrorClip = ctx.gl.clippingPlanes;
2791
- const wasMirrorVisible = mesh.visible;
2792
- mesh.visible = false;
2793
- mirrorClipPlane.constant = -(surfaceY - WATERLINE_CLIP_SLACK);
2794
- ctx.gl.clippingPlanes = mirrorClipPlanes;
2795
- ctx.gl.setRenderTarget(this.mirrorTarget);
2796
- ctx.gl.clear(true, true, false);
2797
- ctx.gl.render(ctx.scene, mirrorCam);
2798
- ctx.gl.setRenderTarget(prevMirrorTarget);
2799
- ctx.gl.clippingPlanes = prevMirrorClip;
2800
- mesh.visible = wasMirrorVisible;
2873
+ if (this.lastMirrorAt === 0 || now - this.lastMirrorAt >= this.rp("mirrorInterval")) {
2874
+ this.lastMirrorAt = now;
2875
+ const prevMirrorTarget = ctx.gl.getRenderTarget();
2876
+ const prevMirrorClip = ctx.gl.clippingPlanes;
2877
+ const wasMirrorVisible = mesh.visible;
2878
+ mesh.visible = false;
2879
+ mirrorClipPlane.constant = -(surfaceY - WATERLINE_CLIP_SLACK);
2880
+ ctx.gl.clippingPlanes = mirrorClipPlanes;
2881
+ ctx.gl.setRenderTarget(this.mirrorTarget);
2882
+ ctx.gl.clear(true, true, false);
2883
+ hideForWaterPass(ctx.scene, this._passHidden);
2884
+ ctx.gl.render(ctx.scene, mirrorCam);
2885
+ restoreForWaterPass(this._passHidden);
2886
+ ctx.gl.setRenderTarget(prevMirrorTarget);
2887
+ ctx.gl.clippingPlanes = prevMirrorClip;
2888
+ mesh.visible = wasMirrorVisible;
2889
+ }
2801
2890
  u.uMirrorMap.value = this.mirrorTarget.texture;
2802
2891
  u.uMirrorMatrix.value.copy(this.mirrorMatrix);
2803
2892
  u.uUseMirror.value = 1;
@@ -2840,7 +2929,9 @@ var Water3D = class Water3D extends Node3D {
2840
2929
  ctx.scene.overrideMaterial = depthOnlyMaterial;
2841
2930
  ctx.scene.background = null;
2842
2931
  ctx.gl.autoClear = false;
2932
+ hideForWaterPass(ctx.scene, this._passHidden);
2843
2933
  ctx.gl.render(ctx.scene, ctx.camera);
2934
+ restoreForWaterPass(this._passHidden);
2844
2935
  ctx.scene.overrideMaterial = prevOverride;
2845
2936
  ctx.scene.background = prevBackground;
2846
2937
  ctx.gl.setRenderTarget(prevTarget);
package/dist/gameplay.js CHANGED
@@ -1,2 +1,2 @@
1
- import { C as FollowCamera, D as Health, E as DamageOnContact, O as Collector, S as restartScene, T as phaseOf, _ as hitStop, a as Wander, b as GameFlow, c as Projectile, d as PathFollow, f as Oscillate, g as Cooldown, h as CameraShake, i as WaveSpawner, k as Chase, l as Pickup, m as Lifetime, n as registerGameplayBehaviors, o as Spawner, p as MoveTo, r as ZombieAI, s as ScoreKeeper, t as GAMEPLAY_BEHAVIORS, u as Patrol, v as screenFlash, w as DayNight, x as goToScene, y as Interactable } from "./gameplay-Dib5mNFD.js";
1
+ import { C as FollowCamera, D as Health, E as DamageOnContact, O as Collector, S as restartScene, T as phaseOf, _ as hitStop, a as Wander, b as GameFlow, c as Projectile, d as PathFollow, f as Oscillate, g as Cooldown, h as CameraShake, i as WaveSpawner, k as Chase, l as Pickup, m as Lifetime, n as registerGameplayBehaviors, o as Spawner, p as MoveTo, r as ZombieAI, s as ScoreKeeper, t as GAMEPLAY_BEHAVIORS, u as Patrol, v as screenFlash, w as DayNight, x as goToScene, y as Interactable } from "./gameplay-BJ5gXIks.js";
2
2
  export { CameraShake, Chase, Collector, Cooldown, DamageOnContact, DayNight, FollowCamera, GAMEPLAY_BEHAVIORS, GameFlow, Health, Interactable, Lifetime, MoveTo, Oscillate, PathFollow, Patrol, Pickup, Projectile, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, goToScene, hitStop, phaseOf, registerGameplayBehaviors, restartScene, screenFlash };
package/dist/index.js CHANGED
@@ -295,6 +295,6 @@ function newUid() {
295
295
  //#endregion
296
296
  //#region src/index.ts
297
297
  /** Engine version. Kept in sync with package.json by the release pipeline. */
298
- const VERSION = "0.22.0";
298
+ const VERSION = "0.24.0";
299
299
  //#endregion
300
300
  export { AudioBuses, AudioPlayer, Behavior, CONST_REF_KEY, Engine, HudLayer, IncantoError, InputMap, LogManager, MusicManager, Node, ORDER_GROUP_BASE, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, ParticleSim, ROLLOFF_MODELS, Rng, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, Scene, SceneTree, SfxEngine, Signal, Timer, TouchControls, UiBanner, UiBar, UiButton, UiDialogue, UiText, VERSION, WebAudioMusicBackend, applyParticlePreset, assetUrls, attachTouchControls, auditScene, clearBehaviors, clearRegistry, computeViewport, createNode, createNoise2D, createSaveStore, crossfadeGains, duplicateNode, effectiveOrder, fadeGain, findPath, getBehavior, getNodeSchema, getNodeSignals, getNodeType, gridFromRows, isAudioContextAvailable, isConstRef, joystickVector, jsonClone, jsonEquals, jsonKind, loadScene, mergeStaticSignals, newUid, parseNodePath, preloadUrls, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, replay, resolveConstants, resolveRendering, resolveViewport, serializeNode, spatialGain, spatialPan, startRecording, synthSfx };
@@ -1,8 +1,8 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
2
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
3
- import { I as Node3D, L as validateCollider3D, M as CharacterBody3D, N as PhysicsBody3D, P as RigidBody3D, j as Area3D } from "./gameplay-Dib5mNFD.js";
3
+ import { I as Node3D, L as validateCollider3D, M as CharacterBody3D, N as PhysicsBody3D, P as RigidBody3D, j as Area3D } from "./gameplay-BJ5gXIks.js";
4
4
  import { n as registerDebugSource } from "./debug-draw-CZmOYjL2.js";
5
- import { T as Terrain3D, k as Joint3D } from "./register-CHgVdSbp.js";
5
+ import { T as Terrain3D, k as Joint3D } from "./register-CpJORtm4.js";
6
6
  import { Euler, Quaternion } from "three";
7
7
  //#region src/3d/physics/physics-3d.ts
8
8
  var physics_3d_exports = /* @__PURE__ */ __exportAll({
package/dist/react.js CHANGED
@@ -156,7 +156,7 @@ function IncantoCanvas(props) {
156
156
  pointer: latest.pointer,
157
157
  ...keyboard !== void 0 ? { keyboard } : {}
158
158
  };
159
- const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-C3uiw80V.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-B-M1zune.js").then((n) => n.n)).createGame2D(o)))(opts);
159
+ const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-DjWIgtQ_.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-DrcEgRup.js").then((n) => n.n)).createGame2D(o)))(opts);
160
160
  if (disposed) {
161
161
  next.dispose();
162
162
  return;
@@ -4,7 +4,7 @@ import { t as Rng } from "./rng-DP-SR7eg.js";
4
4
  import { i as getNodeSchema, l as registerNode } from "./registry-BVJ2HbCn.js";
5
5
  import { t as createNoise2D } from "./noise-CGUMx44x.js";
6
6
  import { i as applyParticlePreset, r as PARTICLE_PRESET_NAMES, t as ParticleSim } from "./particle-sim-Bw7hB93B.js";
7
- import { A as Water3D, B as colliderFootDrop, F as StaticBody3D, I as Node3D, M as CharacterBody3D, N as PhysicsBody3D, P as RigidBody3D, j as Area3D } from "./gameplay-Dib5mNFD.js";
7
+ import { A as Water3D, B as colliderFootDrop, F as StaticBody3D, I as Node3D, M as CharacterBody3D, N as PhysicsBody3D, P as RigidBody3D, j as Area3D } from "./gameplay-BJ5gXIks.js";
8
8
  import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
9
9
  import { AdditiveBlending, AnimationClip, AnimationMixer, Box3, BoxGeometry, BufferAttribute, BufferGeometry, CanvasTexture, CapsuleGeometry, Color, ConeGeometry, CylinderGeometry, DataTexture, DirectionalLight, DoubleSide, DynamicDrawUsage, Euler, Group, IcosahedronGeometry, ImageBitmapLoader, InstancedBufferAttribute, InstancedMesh, LinearFilter, LoopOnce, LoopRepeat, Matrix4, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshPhysicalMaterial, MeshStandardMaterial, NearestFilter, NoBlending, NormalBlending, PerspectiveCamera, PlaneGeometry, PointLight, Points, PointsMaterial, Quaternion, QuaternionKeyframeTrack, RGBADepthPacking, RGBAFormat, RepeatWrapping, SRGBColorSpace, ShaderChunk, ShaderMaterial, SphereGeometry, Texture, TextureLoader, UniformsLib, UniformsUtils, Vector3, Vector4, VectorKeyframeTrack } from "three";
10
10
  import { clone } from "three/addons/utils/SkeletonUtils.js";
@@ -7100,7 +7100,11 @@ void main() {
7100
7100
  // ── edges ───────────────────────────────────────────────────────────────
7101
7101
  // the ribbon is built wider than the channel; what makes its outline is the
7102
7102
  // water running out, so bars and boulders cut it exactly like the ground does
7103
- float edge = smoothstep(0.0, 0.06, column) * (1.0 - smoothstep(0.84, 1.0, abs(across)));
7103
+ // The bank is where the water RUNS OUT, and it runs out over centimetres of
7104
+ // depth spread across metres of ground — a 6 cm ramp cut a hard line that
7105
+ // read as vinyl laid on the grass. Fade over a real wading depth instead, and
7106
+ // let the across-fade start earlier so the ribbon never ends on an edge.
7107
+ float edge = smoothstep(0.0, 0.22, column) * (1.0 - smoothstep(0.7, 1.0, abs(across)));
7104
7108
  float alpha = clamp(max(hide * uOpacity, fresnel * 0.85), 0.0, 1.0);
7105
7109
  alpha = clamp(max(alpha, foam * 0.95) * edge, 0.0, 1.0);
7106
7110
 
@@ -7465,9 +7469,6 @@ var River3D = class River3D extends Node3D {
7465
7469
  transparent: true,
7466
7470
  depthTest: true,
7467
7471
  depthWrite: false,
7468
- polygonOffset: true,
7469
- polygonOffsetFactor: -2,
7470
- polygonOffsetUnits: -4,
7471
7472
  side: DoubleSide
7472
7473
  });
7473
7474
  }
package/dist/test.js CHANGED
@@ -4,9 +4,9 @@ import { t as IncantoError } from "./errors-BpWbnbb_.js";
4
4
  import { t as auditScene } from "./audit-C6rMyict.js";
5
5
  import { n as jsonEquals, t as jsonClone } from "./json-BLk7H2Qa.js";
6
6
  import { i as getNodeSchema, s as mergeStaticProps } from "./registry-BVJ2HbCn.js";
7
- import { n as registerGameplayBehaviors } from "./gameplay-Dib5mNFD.js";
7
+ import { n as registerGameplayBehaviors } from "./gameplay-BJ5gXIks.js";
8
8
  import { t as registerNodes2D } from "./register-CvpSUU3O.js";
9
- import { t as registerNodes3D } from "./register-CHgVdSbp.js";
9
+ import { t as registerNodes3D } from "./register-CpJORtm4.js";
10
10
  import { t as registerNodesNet } from "./register-BFFE1Mh1.js";
11
11
  //#region src/test/index.ts
12
12
  /**
@@ -127,7 +127,7 @@ async function runScript(json, opts) {
127
127
  const { enablePhysics2D } = await import("./physics-2d-DiVFFlH3.js").then((n) => n.r);
128
128
  await enablePhysics2D(engine);
129
129
  } else if (physics === "3d" || physics === "auto" && scene.dimension === "3d") {
130
- const { enablePhysics3D } = await import("./physics-3d-DLPPRNu4.js").then((n) => n.r);
130
+ const { enablePhysics3D } = await import("./physics-3d-CpIB9C-F.js").then((n) => n.r);
131
131
  await enablePhysics3D(engine);
132
132
  }
133
133
  const failures = [];
@@ -232,7 +232,7 @@ async function createPlaySession(json, opts = {}) {
232
232
  const { enablePhysics2D } = await import("./physics-2d-DiVFFlH3.js").then((n) => n.r);
233
233
  await enablePhysics2D(engine);
234
234
  } else if (physics === "3d" || physics === "auto" && scene.dimension === "3d") {
235
- const { enablePhysics3D } = await import("./physics-3d-DLPPRNu4.js").then((n) => n.r);
235
+ const { enablePhysics3D } = await import("./physics-3d-CpIB9C-F.js").then((n) => n.r);
236
236
  await enablePhysics3D(engine);
237
237
  }
238
238
  const stepMs = 1e3 / (opts.fixedHz ?? 60);
@@ -1 +1 @@
1
- import{t as e}from"./index-DAzNRDSQ.js";async function t(t){return new n((await e(()=>import(`./GameServer-C56iOUgF.js`),[],import.meta.url)).GameServer,t)}var n=class{raw;active=new Map;reconnecting=!1;disposed=!1;constructor(e,t){this.raw=new e({...t})}get account(){return this.raw.account}get connected(){return this.raw.connected}connect(){return this.raw.connected?Promise.resolve(!0):(this.disposed=!1,this.rawConnect())}rawConnect(){return this.raw.connect({onDisconnect:()=>void this.reconnect()})}disconnect(){this.disposed=!0;for(let e of this.active.values())e.off();return this.active.clear(),this.raw.disconnect()}remoteFunction(e,t,n){return this.raw.remoteFunction(e,t,n)}track(e){let t=Symbol(`sub`),n={make:e,off:e()};return this.active.set(t,n),()=>{n.off(),this.active.delete(t)}}async reconnect(){if(!this.disposed&&!this.reconnecting){this.reconnecting=!0;try{await this.rawConnect();for(let e of this.active.values())e.off(),e.off=e.make()}finally{this.reconnecting=!1}}}subscribeRoomState(e,t){return this.track(()=>this.raw.subscribeRoomState(e,t))}subscribeRoomMyState(e,t){return this.track(()=>this.raw.subscribeRoomMyState(e,t))}subscribeRoomAllUserStates(e,t){return this.track(()=>this.raw.subscribeRoomAllUserStates(e,e=>{let n={};for(let t of e??[]){if(!t||typeof t.account!=`string`||t.__leaved)continue;let{account:e,__updated:r,__leaved:i,...a}=t;n[e]=a}t(n)}))}subscribeRoomCollection(e,t,n){return this.track(()=>this.raw.subscribeRoomCollection(e,t,({items:e})=>{let t={};for(let n of e??[])n&&typeof n.__id==`string`&&(t[n.__id]=n);n(t)}))}onRoomMessage(e,t,n){return this.track(()=>this.raw.onRoomMessage(e,t,n))}onRoomUserJoin(e,t){return this.track(()=>this.raw.onRoomUserJoin(e,t))}onRoomUserLeave(e,t){return this.track(()=>this.raw.onRoomUserLeave(e,t))}subscribeGlobalState(e){return this.track(()=>this.raw.subscribeGlobalState(e))}subscribeGlobalMyState(e){return this.track(()=>this.raw.subscribeGlobalMyState(e))}subscribeGlobalUserState(e,t){return this.track(()=>this.raw.subscribeGlobalUserState(e,t))}subscribeGlobalCollection(e,t){return this.track(()=>this.raw.subscribeGlobalCollection(e,({items:e})=>{let n={};for(let t of e??[])t&&typeof t.__id==`string`&&(n[t.__id]=t);t(n)}))}subscribeAsset(e,t){return this.track(()=>this.raw.subscribeAsset(e,t))}onGlobalMessage(e,t){return this.track(()=>this.raw.onGlobalMessage(e,t))}};export{t as createAgent8Server};
1
+ import{t as e}from"./index-B5y_MdYb.js";async function t(t){return new n((await e(()=>import(`./GameServer-C56iOUgF.js`),[],import.meta.url)).GameServer,t)}var n=class{raw;active=new Map;reconnecting=!1;disposed=!1;constructor(e,t){this.raw=new e({...t})}get account(){return this.raw.account}get connected(){return this.raw.connected}connect(){return this.raw.connected?Promise.resolve(!0):(this.disposed=!1,this.rawConnect())}rawConnect(){return this.raw.connect({onDisconnect:()=>void this.reconnect()})}disconnect(){this.disposed=!0;for(let e of this.active.values())e.off();return this.active.clear(),this.raw.disconnect()}remoteFunction(e,t,n){return this.raw.remoteFunction(e,t,n)}track(e){let t=Symbol(`sub`),n={make:e,off:e()};return this.active.set(t,n),()=>{n.off(),this.active.delete(t)}}async reconnect(){if(!this.disposed&&!this.reconnecting){this.reconnecting=!0;try{await this.rawConnect();for(let e of this.active.values())e.off(),e.off=e.make()}finally{this.reconnecting=!1}}}subscribeRoomState(e,t){return this.track(()=>this.raw.subscribeRoomState(e,t))}subscribeRoomMyState(e,t){return this.track(()=>this.raw.subscribeRoomMyState(e,t))}subscribeRoomAllUserStates(e,t){return this.track(()=>this.raw.subscribeRoomAllUserStates(e,e=>{let n={};for(let t of e??[]){if(!t||typeof t.account!=`string`||t.__leaved)continue;let{account:e,__updated:r,__leaved:i,...a}=t;n[e]=a}t(n)}))}subscribeRoomCollection(e,t,n){return this.track(()=>this.raw.subscribeRoomCollection(e,t,({items:e})=>{let t={};for(let n of e??[])n&&typeof n.__id==`string`&&(t[n.__id]=n);n(t)}))}onRoomMessage(e,t,n){return this.track(()=>this.raw.onRoomMessage(e,t,n))}onRoomUserJoin(e,t){return this.track(()=>this.raw.onRoomUserJoin(e,t))}onRoomUserLeave(e,t){return this.track(()=>this.raw.onRoomUserLeave(e,t))}subscribeGlobalState(e){return this.track(()=>this.raw.subscribeGlobalState(e))}subscribeGlobalMyState(e){return this.track(()=>this.raw.subscribeGlobalMyState(e))}subscribeGlobalUserState(e,t){return this.track(()=>this.raw.subscribeGlobalUserState(e,t))}subscribeGlobalCollection(e,t){return this.track(()=>this.raw.subscribeGlobalCollection(e,({items:e})=>{let n={};for(let t of e??[])t&&typeof t.__id==`string`&&(n[t.__id]=t);t(n)}))}subscribeAsset(e,t){return this.track(()=>this.raw.subscribeAsset(e,t))}onGlobalMessage(e,t){return this.track(()=>this.raw.onGlobalMessage(e,t))}};export{t as createAgent8Server};