incanto 0.27.0 → 0.28.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-C0bPoURs.js";
2
+ import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-71TJjW1T.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
@@ -909,6 +909,12 @@ declare class Flowers3D extends Node3D {
909
909
  * draping entirely.
910
910
  */
911
911
  drape: boolean | null;
912
+ /**
913
+ * Keep plants out of standing and running water (default true) — a meadow a
914
+ * stream runs through has a bank of flowers, not flowers in the current.
915
+ * Set false for water lilies and marsh planting.
916
+ */
917
+ avoidWater: boolean;
912
918
  /** Drape target: a node path to the Terrain3D. Empty = auto-find the first
913
919
  * Terrain3D in the tree (the zero-config default when `drape` is on). */
914
920
  terrain: string;
@@ -1051,6 +1057,14 @@ declare class Foliage3D extends Node3D implements SunConsumer3D {
1051
1057
  * a terrain appears), false disables draping entirely.
1052
1058
  */
1053
1059
  drape: boolean | null;
1060
+ /**
1061
+ * Keep blades out of standing and running water (default true). Grass does
1062
+ * not grow in a stream: any instance whose ground sits under a `Water3D` or
1063
+ * `River3D` surface is dropped, which is what stops a creek that cut its bed
1064
+ * through a meadow from filling with waving blades. Set false for reeds and
1065
+ * paddy fields, where the plant IS in the water.
1066
+ */
1067
+ avoidWater: boolean;
1054
1068
  /** Drape target: a node path to the Terrain3D. Empty = auto-find the first
1055
1069
  * Terrain3D in the tree (the zero-config default when `drape` is on). */
1056
1070
  terrain: string;
@@ -1119,6 +1133,14 @@ declare class Foliage3D extends Node3D implements SunConsumer3D {
1119
1133
  * fraction of instances into a SECOND InstancedMesh of 5-vertex flower
1120
1134
  * heads (white/yellow/violet per instance).
1121
1135
  */
1136
+ /**
1137
+ * Drop the instances standing in water. The ground each blade drapes onto is
1138
+ * already known here, so the test is one question per candidate — and only
1139
+ * the ones a water surface actually covers pay for it.
1140
+ */
1141
+ private dryOnly;
1142
+ /** This field's own world height (the bed sampler works in local Y). */
1143
+ private worldY;
1122
1144
  private buildMeshField;
1123
1145
  /**
1124
1146
  * The meadow's flower sprinkle: ONE extra InstancedMesh of 5-vertex flower
@@ -1555,29 +1577,152 @@ declare class Particles3D extends Node3D {
1555
1577
  private syncParticles;
1556
1578
  }
1557
1579
  //#endregion
1580
+ //#region src/3d/terrain/heightmap.d.ts
1581
+ /**
1582
+ * A smooth radial depression carved into the terrain — a lake/pond bowl. x/z
1583
+ * are terrain-LOCAL centered meters (the same space `heightAt`/`slopeAt` use);
1584
+ * `radius`/`depth` are meters. The carve is a smoothstep bowl (0 slope at the
1585
+ * rim), so banks blend into the surrounding ground with no cliff.
1586
+ */
1587
+ interface BasinSpec {
1588
+ x: number;
1589
+ z: number;
1590
+ radius: number;
1591
+ /** > 0 carves a bowl; < 0 RAISES a smooth dome mound of that height. */
1592
+ depth: number;
1593
+ }
1594
+ /**
1595
+ * A river/road trench carved along a polyline: the line version of a basin.
1596
+ * `width` is the flat bed, `taper` the bank blend beyond it (default: the bed
1597
+ * width again, which is what makes a walkable V instead of a slot).
1598
+ */
1599
+ interface ChannelSpec {
1600
+ path: readonly (readonly number[])[];
1601
+ width: number;
1602
+ depth: number;
1603
+ taper?: number;
1604
+ }
1605
+ interface HeightmapOptions {
1606
+ /** Terrain extent in meters along x. */
1607
+ width: number;
1608
+ /** Terrain extent in meters along z. */
1609
+ depth: number;
1610
+ /** Grid segments along x (vertices = segsX+1). */
1611
+ segsX: number;
1612
+ /** Grid segments along z (vertices = segsZ+1). */
1613
+ segsZ: number;
1614
+ /** Height scale — realized heights land at roughly 3.5–8× this value. */
1615
+ maxHeight: number;
1616
+ /** Integer seed — same seed, same terrain, every machine. */
1617
+ seed: number;
1618
+ /** Detail persistence (amplitude falloff per detail octave). */
1619
+ roughness?: number;
1620
+ /** Detail octave count. */
1621
+ detail?: number;
1622
+ /** Snap-flatten heights within ±0.6 m of maxHeight·flatThreshold. */
1623
+ flatThreshold?: number;
1624
+ /** Curl the border down a quarter circle and floor it at edgeBottom. */
1625
+ islandEdge?: boolean;
1626
+ /** Quarter-circle radius in meters (clamped to [0, 45]). */
1627
+ edgeWrapRadius?: number;
1628
+ /** Floor y at the outermost ring once the wrap completes. */
1629
+ edgeBottom?: number;
1630
+ /** 0..1 — 1 rounds island corners fully, 0 keeps them square-ish. */
1631
+ edgeCornerSmoothness?: number;
1632
+ /** Smooth radial lake/pond bowls carved into the surface (interior basins). */
1633
+ basins?: BasinSpec[];
1634
+ /** River/road trenches carved along polylines (see {@link ChannelSpec}). */
1635
+ channels?: ChannelSpec[];
1636
+ }
1637
+ interface Heightmap {
1638
+ readonly width: number;
1639
+ readonly depth: number;
1640
+ readonly segsX: number;
1641
+ readonly segsZ: number;
1642
+ /**
1643
+ * Vertex heights INCLUDING edge wrap, `(segsX+1)·(segsZ+1)` long, indexed
1644
+ * `iz·(segsX+1)+ix` with x = -width/2 + ix·cell and z = -depth/2 + iz·cell —
1645
+ * exactly a rotateX(-π/2) PlaneGeometry's vertex order.
1646
+ */
1647
+ readonly heights: Float32Array;
1648
+ /** Realized height range EXCLUDING edge wrap — normalizes splat heights. */
1649
+ readonly minHeight: number;
1650
+ readonly maxHeight: number;
1651
+ /** Bilinear height lookup in terrain-local centered meters (clamps outside). */
1652
+ heightAt(x: number, z: number): number;
1653
+ /** Analytic pipeline height WITHOUT edge wrap (splat domain), same coords. */
1654
+ baseHeight(x: number, z: number): number;
1655
+ /** Splat slope at a point: atan(|∇ baseHeight|) via central differences. */
1656
+ slopeAt(x: number, z: number): number;
1657
+ }
1658
+ /** One splat layer: a texture plus the trapezoid ranges that place it. */
1659
+ interface TerrainLayer {
1660
+ /** Base color texture URL. */
1661
+ texture: string;
1662
+ /** Optional tangent-space normal map URL. */
1663
+ normalMap?: string;
1664
+ /** World-UV tiling factor (UV = worldXZ · repeat · 0.1). Default 2. */
1665
+ repeat?: number;
1666
+ /** Normalized [min, max] over the realized height span. Default [0, 1]. */
1667
+ heightRange?: [number, number];
1668
+ /** [min, max] slope in radians (atan of gradient). Default [0, π/2]. */
1669
+ slopeRange?: [number, number];
1670
+ /** Linear falloff width OUTSIDE heightRange (fraction of span). Default 0.1. */
1671
+ heightBlendRange?: number;
1672
+ /** Linear falloff width outside slopeRange (radians). Default 0.1. */
1673
+ slopeBlendRange?: number;
1674
+ /** PBR roughness scalar for this layer. Default 1. */
1675
+ roughness?: number;
1676
+ /** PBR metalness scalar for this layer. Default 0. */
1677
+ metalness?: number;
1678
+ /** Anti-tiling UV jitter strength. Default 0.15. */
1679
+ uvNoiseIntensity?: number;
1680
+ }
1681
+ /**
1682
+ * Build the deterministic heightfield. Heavy (one noise eval per vertex) —
1683
+ * call once and keep the result.
1684
+ */
1685
+ declare function buildHeightmap(opts: HeightmapOptions): Heightmap;
1686
+ /**
1687
+ * Per-vertex splat weights for up to 4 layers. `height01` is the vertex
1688
+ * height normalized over the heightmap's realized (no-wrap) span, `slopeRad`
1689
+ * is `atan(|∇h|)`. Weight = heightTrapezoid · slopeTrapezoid, sharpened by
1690
+ * `pow(w, 1/blendingStrength)`, then normalized to sum 1 — when nothing
1691
+ * matches, layer 0 takes everything. Always returns exactly 4 entries
1692
+ * (missing layers weigh 0).
1693
+ */
1694
+ declare function splatWeights(height01: number, slopeRad: number, layers: readonly TerrainLayer[], blendingStrength?: number): [number, number, number, number];
1695
+ //#endregion
1558
1696
  //#region src/3d/water/river.d.ts
1697
+ /** Terrain height under a LOCAL-frame point, in the same frame's meters. */
1698
+ type BedSampler = (x: number, z: number) => number;
1699
+ interface RiverCarveOptions {
1700
+ /** Centreline in the TERRAIN'S local frame (that is where channels live). */
1701
+ path: readonly (readonly number[])[];
1702
+ /** Width profile source→mouth (one entry = constant). */
1703
+ widths: readonly number[];
1704
+ /** Water column at the centreline, meters. */
1705
+ depth: number;
1706
+ /** Terrain cell size in meters — a cut finer than this does not exist. */
1707
+ cell: number;
1708
+ /** Ground height BEFORE this river cut anything. */
1709
+ groundAt: BedSampler;
1710
+ }
1559
1711
  /**
1560
- * River centerline math the CPU half of {@link River3D}.
1712
+ * The trench a river digs for itself, as {@link ChannelSpec}s for Terrain3D.
1561
1713
  *
1562
- * Everything here works in the river node's LOCAL frame (the caller hands in a
1563
- * `bedAt(x, z)` sampler that has already been shifted into it), so this module
1564
- * imports nothing from three and stays testable in plain node.
1714
+ * Shared on purpose: `River3D` cuts this at load, and anything that has to
1715
+ * PLACE things against the result a scene generator putting a player, a
1716
+ * bridge and a boulder field on the ground computes the identical cut
1717
+ * instead of approximating it. A generator that guesses differently spawns the
1718
+ * player inside a hill.
1565
1719
  *
1566
- * The shape of a river is NOT authored: it is derived. A path of control
1567
- * points and a width profile is all a scene declares; the ground underneath
1568
- * decides the rest
1569
- *
1570
- * - the **surface profile** follows the bed's descending envelope, so the water
1571
- * runs downhill and never climbs (a rising bed dams it into a still pool);
1572
- * - the **visible width** is whatever the terrain lets the water occupy: every
1573
- * vertex carries its own water column (`surfaceY − bed`), the shader fades to
1574
- * nothing where that reaches zero, so banks, gravel bars and half-drowned
1575
- * boulders carve the ribbon instead of a hand-authored outline;
1576
- * - the **current** obeys continuity (narrow = fast) and grade (steep = fast),
1577
- * which is what makes rapids sit where a channel pinches or tips.
1720
+ * The floor only ever FALLS. Water does not climb, so a bed that climbs is a
1721
+ * river that stops and buries itself; carrying the running minimum downstream
1722
+ * digs through a rise instead, and the cap keeps that from turning a hill into
1723
+ * a canyon.
1578
1724
  */
1579
- /** Terrain height under a LOCAL-frame point, in the same frame's meters. */
1580
- type BedSampler = (x: number, z: number) => number;
1725
+ declare function riverCarveChannels(opts: RiverCarveOptions): ChannelSpec[];
1581
1726
  /** One arc-length sample of the smoothed centerline. */
1582
1727
  interface PathSample {
1583
1728
  x: number;
@@ -1761,6 +1906,12 @@ declare class River3D extends Node3D implements SunConsumer3D {
1761
1906
  /** Rocks are picked per FRAME (nearest to the eye), scanned on a timer. */
1762
1907
  _onRender3D(ctx: RenderContext3D): void;
1763
1908
  /**
1909
+ * @internal Water surface height over a world point, or null where this
1910
+ * river does not run — the question scattered vegetation asks before it
1911
+ * plants a blade (see {@link WetSurface}).
1912
+ */
1913
+ _waterYAt(x: number, z: number): number | null;
1914
+ /**
1764
1915
  * Where a WORLD point sits in the channel — the query gameplay scripts run
1765
1916
  * (steer a raft, drown a torch, decide a ford is too fast to cross). `null`
1766
1917
  * until the river has been built.
@@ -1834,122 +1985,6 @@ declare class River3D extends Node3D implements SunConsumer3D {
1834
1985
  private sweepBodies;
1835
1986
  }
1836
1987
  //#endregion
1837
- //#region src/3d/terrain/heightmap.d.ts
1838
- /**
1839
- * A smooth radial depression carved into the terrain — a lake/pond bowl. x/z
1840
- * are terrain-LOCAL centered meters (the same space `heightAt`/`slopeAt` use);
1841
- * `radius`/`depth` are meters. The carve is a smoothstep bowl (0 slope at the
1842
- * rim), so banks blend into the surrounding ground with no cliff.
1843
- */
1844
- interface BasinSpec {
1845
- x: number;
1846
- z: number;
1847
- radius: number;
1848
- /** > 0 carves a bowl; < 0 RAISES a smooth dome mound of that height. */
1849
- depth: number;
1850
- }
1851
- /**
1852
- * A river/road trench carved along a polyline: the line version of a basin.
1853
- * `width` is the flat bed, `taper` the bank blend beyond it (default: the bed
1854
- * width again, which is what makes a walkable V instead of a slot).
1855
- */
1856
- interface ChannelSpec {
1857
- path: readonly (readonly number[])[];
1858
- width: number;
1859
- depth: number;
1860
- taper?: number;
1861
- }
1862
- interface HeightmapOptions {
1863
- /** Terrain extent in meters along x. */
1864
- width: number;
1865
- /** Terrain extent in meters along z. */
1866
- depth: number;
1867
- /** Grid segments along x (vertices = segsX+1). */
1868
- segsX: number;
1869
- /** Grid segments along z (vertices = segsZ+1). */
1870
- segsZ: number;
1871
- /** Height scale — realized heights land at roughly 3.5–8× this value. */
1872
- maxHeight: number;
1873
- /** Integer seed — same seed, same terrain, every machine. */
1874
- seed: number;
1875
- /** Detail persistence (amplitude falloff per detail octave). */
1876
- roughness?: number;
1877
- /** Detail octave count. */
1878
- detail?: number;
1879
- /** Snap-flatten heights within ±0.6 m of maxHeight·flatThreshold. */
1880
- flatThreshold?: number;
1881
- /** Curl the border down a quarter circle and floor it at edgeBottom. */
1882
- islandEdge?: boolean;
1883
- /** Quarter-circle radius in meters (clamped to [0, 45]). */
1884
- edgeWrapRadius?: number;
1885
- /** Floor y at the outermost ring once the wrap completes. */
1886
- edgeBottom?: number;
1887
- /** 0..1 — 1 rounds island corners fully, 0 keeps them square-ish. */
1888
- edgeCornerSmoothness?: number;
1889
- /** Smooth radial lake/pond bowls carved into the surface (interior basins). */
1890
- basins?: BasinSpec[];
1891
- /** River/road trenches carved along polylines (see {@link ChannelSpec}). */
1892
- channels?: ChannelSpec[];
1893
- }
1894
- interface Heightmap {
1895
- readonly width: number;
1896
- readonly depth: number;
1897
- readonly segsX: number;
1898
- readonly segsZ: number;
1899
- /**
1900
- * Vertex heights INCLUDING edge wrap, `(segsX+1)·(segsZ+1)` long, indexed
1901
- * `iz·(segsX+1)+ix` with x = -width/2 + ix·cell and z = -depth/2 + iz·cell —
1902
- * exactly a rotateX(-π/2) PlaneGeometry's vertex order.
1903
- */
1904
- readonly heights: Float32Array;
1905
- /** Realized height range EXCLUDING edge wrap — normalizes splat heights. */
1906
- readonly minHeight: number;
1907
- readonly maxHeight: number;
1908
- /** Bilinear height lookup in terrain-local centered meters (clamps outside). */
1909
- heightAt(x: number, z: number): number;
1910
- /** Analytic pipeline height WITHOUT edge wrap (splat domain), same coords. */
1911
- baseHeight(x: number, z: number): number;
1912
- /** Splat slope at a point: atan(|∇ baseHeight|) via central differences. */
1913
- slopeAt(x: number, z: number): number;
1914
- }
1915
- /** One splat layer: a texture plus the trapezoid ranges that place it. */
1916
- interface TerrainLayer {
1917
- /** Base color texture URL. */
1918
- texture: string;
1919
- /** Optional tangent-space normal map URL. */
1920
- normalMap?: string;
1921
- /** World-UV tiling factor (UV = worldXZ · repeat · 0.1). Default 2. */
1922
- repeat?: number;
1923
- /** Normalized [min, max] over the realized height span. Default [0, 1]. */
1924
- heightRange?: [number, number];
1925
- /** [min, max] slope in radians (atan of gradient). Default [0, π/2]. */
1926
- slopeRange?: [number, number];
1927
- /** Linear falloff width OUTSIDE heightRange (fraction of span). Default 0.1. */
1928
- heightBlendRange?: number;
1929
- /** Linear falloff width outside slopeRange (radians). Default 0.1. */
1930
- slopeBlendRange?: number;
1931
- /** PBR roughness scalar for this layer. Default 1. */
1932
- roughness?: number;
1933
- /** PBR metalness scalar for this layer. Default 0. */
1934
- metalness?: number;
1935
- /** Anti-tiling UV jitter strength. Default 0.15. */
1936
- uvNoiseIntensity?: number;
1937
- }
1938
- /**
1939
- * Build the deterministic heightfield. Heavy (one noise eval per vertex) —
1940
- * call once and keep the result.
1941
- */
1942
- declare function buildHeightmap(opts: HeightmapOptions): Heightmap;
1943
- /**
1944
- * Per-vertex splat weights for up to 4 layers. `height01` is the vertex
1945
- * height normalized over the heightmap's realized (no-wrap) span, `slopeRad`
1946
- * is `atan(|∇h|)`. Weight = heightTrapezoid · slopeTrapezoid, sharpened by
1947
- * `pow(w, 1/blendingStrength)`, then normalized to sum 1 — when nothing
1948
- * matches, layer 0 takes everything. Always returns exactly 4 entries
1949
- * (missing layers weigh 0).
1950
- */
1951
- declare function splatWeights(height01: number, slopeRad: number, layers: readonly TerrainLayer[], blendingStrength?: number): [number, number, number, number];
1952
- //#endregion
1953
1988
  //#region src/3d/terrain/themes.d.ts
1954
1989
  /** Valid `Terrain3D.theme` values — drives the prop options AND validateJson. */
1955
1990
  declare const TERRAIN_THEMES: readonly ["island", "alpine", "plains", "desert", "grassland", "forest", "savanna", "snow", "wetland", "volcanic", "custom"];
@@ -2534,6 +2569,13 @@ declare class Water3D extends Node3D implements RenderHook3D, SunConsumer3D {
2534
2569
  * the still-water level, which is what a caller comparing heights wants.
2535
2570
  */
2536
2571
  heightAt(x: number, z: number): number;
2572
+ /**
2573
+ * @internal Water surface height over a world point, or null outside this
2574
+ * surface's footprint — what scattered vegetation asks before it plants a
2575
+ * blade (see {@link WetSurface}). The STILL level, not the wave: grass does
2576
+ * not come and go with the swash.
2577
+ */
2578
+ _waterYAt(x: number, z: number): number | null;
2537
2579
  /** Base wave height at world (x, z) — the CPU twin of the active shader.
2538
2580
  * Ripples are excluded on purpose: a splash must not re-trigger itself. */
2539
2581
  private waveOffsetAt;
@@ -2899,4 +2941,4 @@ declare function createNavDebugNode(nav: TerrainNav, opts?: {
2899
2941
  name?: string;
2900
2942
  }): InstancedMesh3D;
2901
2943
  //#endregion
2902
- export { Area3D, AssetStore3D, type BedSampler, Billboard3D, type BillboardGroupMode, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, type CreateGame3DOptions, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, type DownhillTraceOptions, Environment3D, type Environment3DConfig, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, type FlowerVariety, Flowers3D, type FogEnvironment, Foliage3D, type FoliageKind, type FoliageStyle, type Game3D, type HeightSampler, type Heightmap, type HeightmapOptions, InstancedMesh3D, Joint3D, type JointType3D, LoftMesh3D, type LoftSection, MeshInstance3D, type MeshKind, type MeshMaterialProps, type ModelEntry, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, type Physics3DOptions, PhysicsBody3D, QUARTER_PITCH, type RenderContext3D, type RenderHook3D, Renderer3D, type Renderer3DOptions, type RigView, RigidBody3D, type Ripple, River3D, type RiverHit, type RiverRing, type ShadowsEnvironment, type SkyEnvironment, StaticBody3D, type SunConsumer3D, type SyncOptions, type SyncResult, TERRAIN_THEMES, Terrain3D, type TerrainLayer, type TerrainNav, type TerrainNavOptions, type TerrainTheme, Trail3D, Tree3D, type TreeTier, type TreeType, VOXEL_PALETTE, type VoxelBlock, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, buildHeightmap, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, enablePhysics3D, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, registerNodes3D, resolveFlowerDensity, rigPose, setEnvironment3D, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath };
2944
+ export { Area3D, AssetStore3D, type BedSampler, Billboard3D, type BillboardGroupMode, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, type CreateGame3DOptions, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, type DownhillTraceOptions, Environment3D, type Environment3DConfig, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, type FlowerVariety, Flowers3D, type FogEnvironment, Foliage3D, type FoliageKind, type FoliageStyle, type Game3D, type HeightSampler, type Heightmap, type HeightmapOptions, InstancedMesh3D, Joint3D, type JointType3D, LoftMesh3D, type LoftSection, MeshInstance3D, type MeshKind, type MeshMaterialProps, type ModelEntry, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, type Physics3DOptions, PhysicsBody3D, QUARTER_PITCH, type RenderContext3D, type RenderHook3D, Renderer3D, type Renderer3DOptions, type RigView, RigidBody3D, type Ripple, River3D, type RiverCarveOptions, type RiverHit, type RiverRing, type ShadowsEnvironment, type SkyEnvironment, StaticBody3D, type SunConsumer3D, type SyncOptions, type SyncResult, TERRAIN_THEMES, Terrain3D, type TerrainLayer, type TerrainNav, type TerrainNavOptions, type TerrainTheme, Trail3D, Tree3D, type TreeTier, type TreeType, VOXEL_PALETTE, type VoxelBlock, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, buildHeightmap, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, enablePhysics3D, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, setEnvironment3D, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath };
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 PhysicsBody3D, I as RigidBody3D, L as StaticBody3D, M as WaterCutout3D, N as Area3D, P as CharacterBody3D, R as Node3D, V as WATER_MAX_RIPPLES, j as WATER_CUTOUT_MAX } from "./gameplay-Ddk13pQ6.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-DUAtTqID.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-DcHXS1MA.js";
2
+ import { A as Water3D, F as PhysicsBody3D, I as RigidBody3D, L as StaticBody3D, M as WaterCutout3D, N as Area3D, P as CharacterBody3D, R as Node3D, V as WATER_MAX_RIPPLES, j as WATER_CUTOUT_MAX } from "./gameplay-DEG-TP7D.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-BRgWpNsa.js";
4
+ import { A as Joint3D, C as BoneLookAt3D, D as DEFAULT_TERRAIN_TEXTURE_BASE, E as Terrain3D, F as rigPose, M as cameraRelative, N as keyboardIntensity, O as TERRAIN_THEMES, P as movementState, S as Camera3D, T as Billboard3D, _ as DENSITY_PRESETS, a as Trail3D, b as FLOWER_VARIETIES, c as traceDownhillPath, d as LoftMesh3D, f as DirectionalLight3D, g as Foliage3D, h as MeshInstance3D, i as Tree3D, j as QUARTER_PITCH, k as terrainThemeLayers, l as Particles3D, m as InstancedMesh3D, n as VOXEL_PALETTE, o as River3D, p as OmniLight3D, r as VoxelGrid3D, s as riverCarveChannels, t as registerNodes3D, u as ModelInstance3D, v as Flowers3D, w as BoneAttachment3D, x as CharacterController3D, y as resolveFlowerDensity } from "./register-6R75AC7-.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-4mGzOZ2J.js";
6
+ import { n as enablePhysics3D, t as Physics3D } from "./physics-3d--y5clE2j.js";
7
7
  //#region src/3d/environment-runtime.ts
8
8
  /**
9
9
  * Live environment editing — the renderer re-applies `scene.environment`
@@ -142,4 +142,4 @@ function createNavDebugNode(nav, opts) {
142
142
  return node;
143
143
  }
144
144
  //#endregion
145
- export { Area3D, AssetStore3D, Billboard3D, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, Environment3D, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, Flowers3D, Foliage3D, InstancedMesh3D, Joint3D, LoftMesh3D, MeshInstance3D, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, PhysicsBody3D, QUARTER_PITCH, Renderer3D, RigidBody3D, River3D, StaticBody3D, TERRAIN_THEMES, Terrain3D, Trail3D, Tree3D, VOXEL_PALETTE, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, buildHeightmap, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, enablePhysics3D, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, registerNodes3D, resolveFlowerDensity, rigPose, setEnvironment3D, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath };
145
+ export { Area3D, AssetStore3D, Billboard3D, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, Environment3D, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, Flowers3D, Foliage3D, InstancedMesh3D, Joint3D, LoftMesh3D, MeshInstance3D, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, PhysicsBody3D, QUARTER_PITCH, Renderer3D, RigidBody3D, River3D, StaticBody3D, TERRAIN_THEMES, Terrain3D, Trail3D, Tree3D, VOXEL_PALETTE, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, buildHeightmap, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, enablePhysics3D, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, setEnvironment3D, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath };
@@ -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-Ddk13pQ6.js";
6
+ import { n as registerGameplayBehaviors } from "./gameplay-DEG-TP7D.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";
@@ -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 { B as createCausticsQuad, F as PhysicsBody3D, R as Node3D, n as registerGameplayBehaviors } from "./gameplay-Ddk13pQ6.js";
6
+ import { B as createCausticsQuad, F as PhysicsBody3D, R as Node3D, n as registerGameplayBehaviors } from "./gameplay-DEG-TP7D.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-DcHXS1MA.js";
9
- import { n as enablePhysics3D } from "./physics-3d-4mGzOZ2J.js";
8
+ import { S as Camera3D, f as DirectionalLight3D, t as registerNodes3D, u as ModelInstance3D } from "./register-6R75AC7-.js";
9
+ import { n as enablePhysics3D } from "./physics-3d--y5clE2j.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";
@@ -3565,6 +3565,19 @@ var Water3D = class Water3D extends Node3D {
3565
3565
  const center = worldTranslationOf(this, this._scratchA);
3566
3566
  return center.y + this.waveOffsetAt(x, z, center);
3567
3567
  }
3568
+ /**
3569
+ * @internal Water surface height over a world point, or null outside this
3570
+ * surface's footprint — what scattered vegetation asks before it plants a
3571
+ * blade (see {@link WetSurface}). The STILL level, not the wave: grass does
3572
+ * not come and go with the swash.
3573
+ */
3574
+ _waterYAt(x, z) {
3575
+ const center = worldTranslationOf(this, this._scratchA);
3576
+ const halfX = (this.size[0] ?? 0) / 2;
3577
+ const halfZ = (this.size[1] ?? 0) / 2;
3578
+ if (Math.abs(x - center.x) > halfX || Math.abs(z - center.z) > halfZ) return null;
3579
+ return center.y;
3580
+ }
3568
3581
  /** Base wave height at world (x, z) — the CPU twin of the active shader.
3569
3582
  * Ripples are excluded on purpose: a splash must not re-trigger itself. */
3570
3583
  waveOffsetAt(x, z, center) {
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-Ddk13pQ6.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-DEG-TP7D.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.27.0";
298
+ const VERSION = "0.28.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 { F as PhysicsBody3D, I as RigidBody3D, N as Area3D, P as CharacterBody3D, R as Node3D, z as validateCollider3D } from "./gameplay-Ddk13pQ6.js";
3
+ import { F as PhysicsBody3D, I as RigidBody3D, N as Area3D, P as CharacterBody3D, R as Node3D, z as validateCollider3D } from "./gameplay-DEG-TP7D.js";
4
4
  import { n as registerDebugSource } from "./debug-draw-CZmOYjL2.js";
5
- import { T as Terrain3D, k as Joint3D } from "./register-DcHXS1MA.js";
5
+ import { A as Joint3D, E as Terrain3D } from "./register-6R75AC7-.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-DUAtTqID.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-C0bPoURs.js").then((n) => n.n)).createGame2D(o)))(opts);
159
+ const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-BRgWpNsa.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-71TJjW1T.js").then((n) => n.n)).createGame2D(o)))(opts);
160
160
  if (disposed) {
161
161
  next.dispose();
162
162
  return;