incanto 0.17.2 → 0.18.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/3d.d.ts CHANGED
@@ -1707,6 +1707,18 @@ declare class Terrain3D extends Node3D {
1707
1707
  /** Lake/pond bowls carved into the surface — smooth radial depressions the
1708
1708
  * collider + heightAt + dressing all see (place a Water3D in each). */
1709
1709
  basins: BasinSpec[];
1710
+ /**
1711
+ * WET SAND band: `{ y, band? }` darkens + glosses the splat in a noisy,
1712
+ * breathing band just above height `y` (a waterline) — the trace of the
1713
+ * last swash runup. `band` is the max height above `y` that reads wet
1714
+ * (default 1.1 m). null (default) = off.
1715
+ */
1716
+ wetline: JsonObject | null;
1717
+ private splatUniforms;
1718
+ /** Per-frame wetline clock + prop write — lives in update() so a `static`
1719
+ * subtree keeps the wet edge breathing (the frozen-sync lesson). */
1720
+ private wetTime;
1721
+ override update(dt: number): void;
1710
1722
  /** Loader hook: bad themes/layers/grids fail at LOAD, not at render. */
1711
1723
  static validateJson(node: Node): void;
1712
1724
  private heightmap;
package/dist/3d.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
2
- 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-PSpDDtTa.js";
3
- import { A as Joint3D, B as keyboardIntensity, C as BoneLookAt3D, D as DEFAULT_TERRAIN_TEXTURE_BASE, E as Terrain3D, F as StaticBody3D, H as rigPose, I as Node3D, M as CharacterBody3D, N as PhysicsBody3D, O as TERRAIN_THEMES, P as RigidBody3D, R as QUARTER_PITCH, S as Camera3D, T as Billboard3D, V as movementState, _ as DENSITY_PRESETS, a as VOXEL_PALETTE, b as FLOWER_VARIETIES, c as Trail3D, d as LoftMesh3D, f as DirectionalLight3D, g as Foliage3D, h as MeshInstance3D, i as WATER_MAX_RIPPLES, j as Area3D, k as terrainThemeLayers, l as Particles3D, m as InstancedMesh3D, n as Water3D, o as VoxelGrid3D, p as OmniLight3D, s as Tree3D, t as registerNodes3D, u as ModelInstance3D, v as Flowers3D, w as BoneAttachment3D, x as CharacterController3D, y as resolveFlowerDensity, z as cameraRelative } from "./register-B_PNOtko.js";
2
+ 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-BiT-ZLi6.js";
3
+ import { A as Joint3D, B as keyboardIntensity, C as BoneLookAt3D, D as DEFAULT_TERRAIN_TEXTURE_BASE, E as Terrain3D, F as StaticBody3D, H as rigPose, I as Node3D, M as CharacterBody3D, N as PhysicsBody3D, O as TERRAIN_THEMES, P as RigidBody3D, R as QUARTER_PITCH, S as Camera3D, T as Billboard3D, V as movementState, _ as DENSITY_PRESETS, a as VOXEL_PALETTE, b as FLOWER_VARIETIES, c as Trail3D, d as LoftMesh3D, f as DirectionalLight3D, g as Foliage3D, h as MeshInstance3D, i as WATER_MAX_RIPPLES, j as Area3D, k as terrainThemeLayers, l as Particles3D, m as InstancedMesh3D, n as Water3D, o as VoxelGrid3D, p as OmniLight3D, s as Tree3D, t as registerNodes3D, u as ModelInstance3D, v as Flowers3D, w as BoneAttachment3D, x as CharacterController3D, y as resolveFlowerDensity, z as cameraRelative } from "./register-BWGwa7H7.js";
4
4
  import { n as splatWeights, t as buildHeightmap } from "./heightmap-CroQPEER.js";
5
- import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-DBEnHZqn.js";
5
+ import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-CfeZOpyK.js";
6
6
  //#region src/3d/environment-runtime.ts
7
7
  /**
8
8
  * Live environment editing — the renderer re-applies `scene.environment`
@@ -5,8 +5,8 @@ import { t as IncantoError } from "./errors-BpWbnbb_.js";
5
5
  import { i as resolveRendering, n as attachTouchControls } from "./touch-031PxtCR.js";
6
6
  import { n as registerGameplayBehaviors } from "./gameplay-sSqrUcnz.js";
7
7
  import { t as debugSources } from "./debug-draw-CZmOYjL2.js";
8
- import { I as Node3D, N as PhysicsBody3D, S as Camera3D, f as DirectionalLight3D, r as createCausticsQuad, t as registerNodes3D, u as ModelInstance3D } from "./register-B_PNOtko.js";
9
- import { n as enablePhysics3D } from "./physics-3d-DBEnHZqn.js";
8
+ import { I as Node3D, N as PhysicsBody3D, S as Camera3D, f as DirectionalLight3D, r as createCausticsQuad, t as registerNodes3D, u as ModelInstance3D } from "./register-BWGwa7H7.js";
9
+ import { n as enablePhysics3D } from "./physics-3d-CfeZOpyK.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";
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.17.2";
298
+ const VERSION = "0.18.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,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
2
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
3
3
  import { n as registerDebugSource } from "./debug-draw-CZmOYjL2.js";
4
- import { A as Joint3D, E as Terrain3D, I as Node3D, L as validateCollider3D, M as CharacterBody3D, N as PhysicsBody3D, P as RigidBody3D, j as Area3D } from "./register-B_PNOtko.js";
4
+ import { A as Joint3D, E as Terrain3D, I as Node3D, L as validateCollider3D, M as CharacterBody3D, N as PhysicsBody3D, P as RigidBody3D, j as Area3D } from "./register-BWGwa7H7.js";
5
5
  import { Euler, Quaternion } from "three";
6
6
  //#region src/3d/physics/physics-3d.ts
7
7
  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-PSpDDtTa.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-Ct86zczq.js").then((n) => n.n)).createGame2D(o)))(opts);
159
+ const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-BiT-ZLi6.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-Ct86zczq.js").then((n) => n.n)).createGame2D(o)))(opts);
160
160
  if (disposed) {
161
161
  next.dispose();
162
162
  return;
@@ -546,6 +546,13 @@ varying vec3 vWorldPosition;
546
546
  varying vec2 vUvSplat;
547
547
 
548
548
  // Noise functions - for naturalizing tiling patterns
549
+ // incanto wetline: WET SAND — a darkened, slightly glossy band hugging the
550
+ // waterline (uWetlineY), its upper edge noisy and breathing with the swash.
551
+ // uWetlineY <= -1e8 disables (the default).
552
+ uniform float uWetlineY;
553
+ uniform float uWetlineBand;
554
+ uniform float uWetTime;
555
+
549
556
  float splatHash(vec2 p) {
550
557
  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
551
558
  }
@@ -709,6 +716,22 @@ if(splatTextureCount > 1.0) blendedMetalness += splatMetalness2 * smoothWeight2;
709
716
  if(splatTextureCount > 2.0) blendedMetalness += splatMetalness3 * smoothWeight3;
710
717
  if(splatTextureCount > 3.0) blendedMetalness += splatMetalness4 * smoothWeight4;
711
718
 
719
+ // incanto wetline: darken + gloss the sand just above the waterline. The
720
+ // upper edge is fbm-ragged and BREATHES (slow sin synced roughly to the
721
+ // water's swash cadence) so the wet band reads as the trace of the last
722
+ // runup, not a painted stripe.
723
+ if (uWetlineY > -1.0e8) {
724
+ float above = vWorldPosition.y - uWetlineY;
725
+ float breathe = 0.5 + 0.5 * sin(uWetTime * 0.42 + vWorldPosition.x * 0.03 + vWorldPosition.z * 0.021);
726
+ float top = uWetlineBand * (0.5 + 0.5 * breathe);
727
+ float ragged = top + (fbm(vec2(vWorldPosition.x, vWorldPosition.z) * 0.35) - 0.5) * uWetlineBand * 0.8;
728
+ float wet = smoothstep(ragged, ragged * 0.25, above) * smoothstep(-uWetlineBand, -uWetlineBand * 0.2, above);
729
+ // wet sand is first and foremost DARKER; the gleam is mild — a hard
730
+ // roughness cut mirrored the sky and read as white glare from the air
731
+ splatColor.rgb *= 1.0 - wet * 0.38;
732
+ blendedRoughness = mix(blendedRoughness, blendedRoughness * 0.78, wet);
733
+ }
734
+
712
735
  diffuseColor = vec4(splatColor.rgb, diffuseColor.a);
713
736
  `;
714
737
  const FRAG_ROUGHNESS = `
@@ -793,6 +816,9 @@ function injectTerrainSplatShader(shader, cfg) {
793
816
  shader.uniforms[`uvNoiseIntensity${n}`] = { value: cfg.uvNoiseIntensity[i] ?? .15 };
794
817
  }
795
818
  shader.uniforms.splatTextureCount = { value: Math.min(4, cfg.layerCount) };
819
+ shader.uniforms.uWetlineY = { value: -1e9 };
820
+ shader.uniforms.uWetlineBand = { value: 1.1 };
821
+ shader.uniforms.uWetTime = { value: 0 };
796
822
  shader.uniforms.splatEnvCut = { value: cfg.envCut };
797
823
  shader.vertexShader = injectAfter(shader.vertexShader, "#include <common>", VERT_COMMON);
798
824
  shader.vertexShader = injectAfter(shader.vertexShader, "#include <begin_vertex>", VERT_BEGIN);
@@ -1184,7 +1210,8 @@ var Terrain3D = class extends Node3D {
1184
1210
  islandEdge: { default: null },
1185
1211
  layers: { default: [] },
1186
1212
  textureBase: { default: DEFAULT_TERRAIN_TEXTURE_BASE },
1187
- basins: { default: [] }
1213
+ basins: { default: [] },
1214
+ wetline: { default: null }
1188
1215
  };
1189
1216
  /** [width, depth] extent in meters, centered on the node. */
1190
1217
  size = [200, 200];
@@ -1211,6 +1238,26 @@ var Terrain3D = class extends Node3D {
1211
1238
  /** Lake/pond bowls carved into the surface — smooth radial depressions the
1212
1239
  * collider + heightAt + dressing all see (place a Water3D in each). */
1213
1240
  basins = [];
1241
+ /**
1242
+ * WET SAND band: `{ y, band? }` darkens + glosses the splat in a noisy,
1243
+ * breathing band just above height `y` (a waterline) — the trace of the
1244
+ * last swash runup. `band` is the max height above `y` that reads wet
1245
+ * (default 1.1 m). null (default) = off.
1246
+ */
1247
+ wetline = null;
1248
+ splatUniforms = null;
1249
+ /** Per-frame wetline clock + prop write — lives in update() so a `static`
1250
+ * subtree keeps the wet edge breathing (the frozen-sync lesson). */
1251
+ wetTime = 0;
1252
+ update(dt) {
1253
+ this.wetTime += dt;
1254
+ const u = this.splatUniforms;
1255
+ if (!u) return;
1256
+ const w = this.wetline;
1257
+ if (u.uWetlineY) u.uWetlineY.value = typeof w?.y === "number" ? w.y : -1e9;
1258
+ if (u.uWetlineBand) u.uWetlineBand.value = typeof w?.band === "number" ? w.band : 1.1;
1259
+ if (u.uWetTime) u.uWetTime.value = this.wetTime;
1260
+ }
1214
1261
  /** Loader hook: bad themes/layers/grids fail at LOAD, not at render. */
1215
1262
  static validateJson(node) {
1216
1263
  const t = node;
@@ -1225,6 +1272,11 @@ var Terrain3D = class extends Node3D {
1225
1272
  if (!Number.isInteger(t.detail) || t.detail < 0) throw new IncantoError("BAD_FORMAT", `Terrain3D '${node.name}' detail must be an integer ≥ 0 (octave count), got ${t.detail}.`, { prop: "detail" });
1226
1273
  if (!(t.flatThreshold >= 0) || !Number.isFinite(t.flatThreshold)) throw new IncantoError("BAD_FORMAT", `Terrain3D '${node.name}' flatThreshold must be a finite number ≥ 0, got ${t.flatThreshold}.`, { prop: "flatThreshold" });
1227
1274
  if (t.islandEdge !== null && typeof t.islandEdge !== "boolean") throw new IncantoError("BAD_FORMAT", `Terrain3D '${node.name}' islandEdge must be true, false or null (null = theme default), got ${JSON.stringify(t.islandEdge)}.`, { prop: "islandEdge" });
1275
+ const wl = t.wetline;
1276
+ if (wl !== null) {
1277
+ if (typeof wl !== "object" || Array.isArray(wl) || !Number.isFinite(wl.y)) throw new IncantoError("BAD_FORMAT", `Terrain3D '${node.name}' wetline must be null or { y, band? } with a finite y, got ${JSON.stringify(t.wetline)}.`, { prop: "wetline" });
1278
+ if (wl.band !== void 0 && !(wl.band > 0)) throw new IncantoError("BAD_FORMAT", `Terrain3D '${node.name}' wetline.band must be > 0 meters, got ${JSON.stringify(wl.band)}.`, { prop: "wetline" });
1279
+ }
1228
1280
  if (!Array.isArray(t.basins)) throw new IncantoError("BAD_FORMAT", `Terrain3D '${node.name}' basins must be an array of { x, z, radius, depth }, got ${JSON.stringify(t.basins)}.`, { prop: "basins" });
1229
1281
  t.basins.forEach((b, i) => {
1230
1282
  if (!b || typeof b !== "object" || !Number.isFinite(b.x) || !Number.isFinite(b.z) || !(b.radius > 0) || !(b.depth > 0)) throw new IncantoError("BAD_FORMAT", `Terrain3D '${node.name}' basins[${i}] needs finite x, z and positive radius, depth, got ${JSON.stringify(b)}.`, { prop: "basins" });
@@ -1397,6 +1449,7 @@ var Terrain3D = class extends Node3D {
1397
1449
  };
1398
1450
  material.onBeforeCompile = (shader) => {
1399
1451
  injectTerrainSplatShader(shader, cfg);
1452
+ this.splatUniforms = shader.uniforms;
1400
1453
  };
1401
1454
  material.customProgramCacheKey = () => `incanto-terrain-splat:${hasNormalMaps ? 1 : 0}`;
1402
1455
  return material;
@@ -10463,6 +10516,10 @@ uniform vec4 uRipples[8];
10463
10516
  uniform float uSwellAmplitude;
10464
10517
  uniform vec2 uSwellDir;
10465
10518
  uniform float uSwellWavelength;
10519
+ // incanto shore: the SWASH SURGE shares the shore-waves dial — a very long
10520
+ // slow bulge marching shoreward; ±9 cm of water height walks the waterline
10521
+ // meters up and down a gentle beach (the lapping runup).
10522
+ uniform float uShoreWaves;
10466
10523
  // incanto presets: the edge-fade ring exists to melt BIG water into terrain
10467
10524
  // shores — inside an exact-walled basin (pool/pond) it carves a visible
10468
10525
  // elliptical cliff instead, so those presets turn it off.
@@ -10575,8 +10632,18 @@ float getSwell(vec2 p) {
10575
10632
 
10576
10633
  // incanto: waves + swell + ripples — used for displacement AND the normal
10577
10634
  // samples so every layer catches the light like real waves.
10635
+ // incanto shore: two incommensurate long surges — the waterline breathes in
10636
+ // wave-sets instead of a metronome tide
10637
+ float getSwash(vec2 p) {
10638
+ if (uShoreWaves <= 0.0) return 0.0;
10639
+ float along = dot(p, uSwellDir);
10640
+ return uShoreWaves *
10641
+ (0.06 * sin(along * 0.045 - uTime * 0.42) + 0.045 * sin(along * 0.11 - uTime * 0.71 + 1.3));
10642
+ }
10643
+
10578
10644
  float getHeight(float x, float z) {
10579
- return getElevation(x, z) + getSwell(vec2(x, z)) + getRippleHeight(vec2(x, z));
10645
+ return getElevation(x, z) + getSwell(vec2(x, z)) + getSwash(vec2(x, z)) +
10646
+ getRippleHeight(vec2(x, z));
10580
10647
  }
10581
10648
 
10582
10649
  void main() {
@@ -11014,15 +11081,21 @@ void main() {
11014
11081
  float depthDiff = linearWaterDepth - linearSceneDepth;
11015
11082
  waterViewDepth = max(-depthDiff, 0.0);
11016
11083
 
11084
+ // waterline dither: on a near-flat beach one half-res depth texel spans a
11085
+ // wide screen block at grazing view, so these thresholds cut staircase
11086
+ // notches along the swash edge — jitter the boundary a few cm with world
11087
+ // noise and the seam breaks into a ragged organic waterline instead.
11088
+ float seamJitter = (noise(vWorldPosition.xz * 2.3) - 0.5) * 0.06;
11089
+
11017
11090
  // 🎯 Two-step approach
11018
11091
  // Step 1: Discard completely overlapping parts
11019
- float hardDiscardThreshold = 0.1;
11092
+ float hardDiscardThreshold = 0.1 + seamJitter;
11020
11093
  if (depthDiff > hardDiscardThreshold) {
11021
11094
  discard; // Completely remove definitively overlapping pixels
11022
11095
  }
11023
11096
 
11024
11097
  // Step 2: Gradual transparency for border parts
11025
- float softDiscardStart = -0.05; // Start fade slightly ahead
11098
+ float softDiscardStart = -0.05 + seamJitter; // Start fade slightly ahead
11026
11099
  float softDiscardEnd = hardDiscardThreshold;
11027
11100
 
11028
11101
  if (depthDiff > softDiscardStart) {
@@ -11179,15 +11252,16 @@ void main() {
11179
11252
  vec3 sceneColor = texture2D(uSceneColor, refractedUV, 1.75).rgb;
11180
11253
  // incanto presets: above-water caustics — reconstruct the sampled
11181
11254
  // bottom's world position along the view ray and light it with the
11182
- // shared caustic web. Strongest through the first meters of water
11183
- // (a pool floor dances, the deep sea does not), distance-faded so far
11184
- // shallows never shimmer-alias.
11255
+ // shared caustic web. Needs a focusing column of water (a centimeters-
11256
+ // deep swash film shows no web) and a close viewer: past ~30m each
11257
+ // pixel integrates many caustic cells and the additive web averages
11258
+ // into a solid white sheet over any flat shallow (aerial sandbar bug).
11185
11259
  if (uCausticsAbove > 0.0) {
11186
11260
  vec3 bottomWorld = cameraPosition + viewDirection * refrT;
11187
11261
  float below = uWaterCenter.y - bottomWorld.y;
11188
11262
  if (below > 0.05) {
11189
- float reach = 1.0 - smoothstep(0.2, 9.0, below);
11190
- float causticFade = 1.0 - smoothstep(60.0, 200.0, camDist);
11263
+ float reach = smoothstep(0.05, 0.5, below) * (1.0 - smoothstep(0.2, 9.0, below));
11264
+ float causticFade = 1.0 - smoothstep(28.0, 90.0, camDist);
11191
11265
  float cw = caustic(bottomWorld.xz * 0.42, uTime * 0.7) * 0.65
11192
11266
  + caustic(bottomWorld.xz * 0.72 + 30.0, uTime * 0.55) * 0.35;
11193
11267
  sceneColor += vec3(0.87, 0.96, 1.0) * (cw * uCausticsAbove * reach * causticFade);
@@ -11305,8 +11379,18 @@ void main() {
11305
11379
  float breakup = noise(vWorldPosition.xz * 0.3 + uTime * vec2(0.06, 0.04));
11306
11380
  float lace = noise(vWorldPosition.xz * 2.2 - uTime * vec2(0.18, 0.1));
11307
11381
  front *= (0.45 + 0.55 * breakup) * (0.55 + 0.45 * lace) * (0.35 + 0.65 * sets);
11308
- float zone = smoothstep(3.4, 1.2, vertDepth) * smoothstep(0.02, 0.2, vertDepth);
11382
+ // no fronts in the centimeters-deep SHEET-FLOW film (an enclosed flat
11383
+ // fizzed solid white from the air) — breakers need ~knee depth to form
11384
+ float zone = smoothstep(3.4, 1.2, vertDepth) * smoothstep(0.12, 0.38, vertDepth);
11309
11385
  foamAmount = max(foamAmount, clamp(uShoreWaves * front * zone * 1.5, 0.0, 1.0));
11386
+ // waterline LACE — fizzing bubbles where the runup meets sand. On a
11387
+ // near-FLAT bar the 0–30 cm depth band is tens of meters wide, so an
11388
+ // ungated lace carpeted whole flats in white — a slow patch gate keeps
11389
+ // it as drifting foam streaks instead (real tidal-flat scum lines).
11390
+ float lacePatch = smoothstep(0.4, 0.8, noise(vWorldPosition.xz * 0.5 + uTime * vec2(0.06, 0.045)));
11391
+ float lace2 = smoothstep(0.24, 0.02, vertDepth) *
11392
+ (0.35 + 0.65 * noise(vWorldPosition.xz * 3.1 + uTime * vec2(0.5, 0.35)));
11393
+ foamAmount = max(foamAmount, clamp(uShoreWaves * lace2 * lacePatch * 0.4, 0.0, 1.0));
11310
11394
  }
11311
11395
  }
11312
11396
  // incanto swell: whitecaps — foam eats the TOPS of the tallest crests in
@@ -11613,23 +11697,23 @@ const WATER_PRESETS = {
11613
11697
  swell: .34,
11614
11698
  swellWavelength: 52,
11615
11699
  whitecaps: .15,
11616
- absorption: .15,
11700
+ absorption: .17,
11617
11701
  opacity: .85,
11618
11702
  detailStrength: .17,
11619
11703
  sunIntensity: .85,
11620
11704
  colors: {
11621
- trough: "#20444f",
11622
- surface: "#3d6b74",
11623
- peak: "#93b4b0"
11705
+ trough: "#175360",
11706
+ surface: "#2f8792",
11707
+ peak: "#9bd8d2"
11624
11708
  },
11625
- color: "#3d6b74",
11709
+ color: "#2f8792",
11626
11710
  causticsAbove: .3,
11627
11711
  shoreWaves: .7,
11628
11712
  reflectionInterval: 400,
11629
11713
  _look: {
11630
11714
  fresnelScale: 1.15,
11631
11715
  reflectivityMax: .93,
11632
- foamRangeScale: 1.15,
11716
+ foamRangeScale: .35,
11633
11717
  foamIntensity: .55
11634
11718
  }
11635
11719
  },
package/dist/test.js CHANGED
@@ -6,7 +6,7 @@ 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
7
  import { n as registerGameplayBehaviors } from "./gameplay-sSqrUcnz.js";
8
8
  import { t as registerNodes2D } from "./register-Djwckzgx.js";
9
- import { t as registerNodes3D } from "./register-B_PNOtko.js";
9
+ import { t as registerNodes3D } from "./register-BWGwa7H7.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-BiIdl51r.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-DBEnHZqn.js").then((n) => n.r);
130
+ const { enablePhysics3D } = await import("./physics-3d-CfeZOpyK.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-BiIdl51r.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-DBEnHZqn.js").then((n) => n.r);
235
+ const { enablePhysics3D } = await import("./physics-3d-CfeZOpyK.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-B756vMqx.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-L774mpvF.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};