incanto 0.10.0 → 0.12.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/editor/index.html CHANGED
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Incanto Scene Editor</title>
7
7
  <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><rect width='16' height='16' rx='3' fill='%236ee7dc'/><text x='8' y='12' text-anchor='middle' font-size='11' font-family='monospace' fill='%230e1018'>i</text></svg>" />
8
- <script type="module" crossorigin src="./assets/index-Dp_cYQx1.js"></script>
8
+ <script type="module" crossorigin src="./assets/index-s0DZuroe.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="./assets/GameServer-C56iOUgF.js">
10
10
  <link rel="stylesheet" crossorigin href="./assets/index-D8QvwvOm.css">
11
11
  </head>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "incanto",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "Vibe-coding-first web game engine SDK — JSON-driven scenes on three.js",
5
5
  "keywords": [
6
6
  "game-engine",
@@ -56,9 +56,14 @@ character stays centered even while the camera is catching up or pulled in by a
56
56
  collision — no jitter.
57
57
 
58
58
  **Camera collision (spring arm).** For the orbit views (`free`/`quarter`/`side`)
59
- the camera won't clip through walls or the ground: each frame it raycasts from
60
- the eye toward the camera and, if a collider blocks the boom, smoothly pulls the
61
- camera in front of it (plus a ground backstop so it never drops below the floor).
59
+ the camera won't clip through walls or the ground: each frame it sweeps a small
60
+ SPHERE (not a thin ray — a ray that skims 10 cm over a wall reports "clear"
61
+ while the wall still fills the frame) from the eye toward the camera and, if a
62
+ collider blocks the boom, smoothly pulls the camera in front of it (plus a
63
+ ground backstop so it never drops below the floor).
64
+ Level-design corollary: walls you want the camera to respect must be TALLER
65
+ than the eye line (`player y + eyeHeight`, ~1.9 m for a default rig) — a
66
+ 1.8 m hedge is below the boom entirely and the camera will look over it.
62
67
  This is on by default (`cameraCollision: true`); set it `false` to get the old raw
63
68
  orbit. Only the STATIC/fixed world stops it — give walls/floors/terrain a
64
69
  `StaticBody3D` collider (collider-less meshes are invisible to the ray, same as to
@@ -141,7 +146,8 @@ A sword in the hand, a hat on the head, sparks on a wingtip — parent them to a
141
146
  - Purely VISUAL: it follows the rendered skeleton, so headless the node stays
142
147
  at its prop transform — keep hit checks range-based from the body, never
143
148
  bone-based.
144
- - `model.boneNames()` lists every bone at runtime when you need to hunt one.
149
+ - `model.boneNames()` lists every bone at runtime when you need to hunt one
150
+ (the editor's inspector offers the same list as a dropdown on the `bone` prop).
145
151
 
146
152
  ## Facing a direction in 3D — the +Z-FORWARD rule (read before turning ANY skin)
147
153
 
@@ -283,6 +283,14 @@ demo into a commercial-looking outdoor scene:
283
283
  dreamier), `strength` how strongly the blurred glow is added back (default
284
284
  0.85; ~1.2 = neon night). One extra half-res blur pass per frame — cheap.
285
285
  Caustics/clouds composites take precedence (pipelines don't stack yet).
286
+ - `post`: the color-grade tail — `{ "vignette"?, "saturation"?, "contrast"? }`.
287
+ `vignette` 0..1 darkens the corners (0.3 = cinematic, 0.6 = heavy mood);
288
+ `saturation` 0..4 (0 = grayscale, 1 = neutral, 1.2 = vivid); `contrast`
289
+ 0.2..3 around mid-gray (1 = neutral). Applied after tone mapping on the same
290
+ composite pass as bloom — declaring `post` WITHOUT `bloom` costs just one
291
+ offscreen pass. The fastest way to give a scene a LOOK: dusk = vignette 0.35
292
+ + saturation 0.85, candy = saturation 1.25 + contrast 1.08. Caustics/clouds
293
+ composites take precedence (pipelines don't stack yet).
286
294
  - `shadows`: `true` | `false` | `{ "mapSize": 1024|2048, "radius": n }`.
287
295
  Truthy makes the main DirectionalLight cast (PCF soft, terrain + trees +
288
296
  meshes cast/receive, mesh grass RECEIVES only). One static ortho box (±75 m
@@ -388,6 +396,33 @@ from a `seed`, with `heightAt(x, z)` for spawning/placement and a
388
396
  `StaticBody3D`). Full themes table, custom layer format and the water/beach
389
397
  pairing live in the **incanto-environment** skill.
390
398
 
399
+ ### Navigation on terrain (`buildTerrainNav` + findPath)
400
+
401
+ Enemies that chase across an open world need paths that respect the surface —
402
+ `buildTerrainNav` samples the heightfield into a walkable grid for the core
403
+ A* (`findPath`), and lifts waypoints back ONTO the surface:
404
+
405
+ ```ts
406
+ import { buildTerrainNav } from 'incanto/3d';
407
+ import { findPath } from 'incanto';
408
+
409
+ const nav = buildTerrainNav(terrain, {
410
+ cellSize: 2, // meters per cell (character-scale corridors)
411
+ maxSlopeDeg: 40, // steeper cells are unwalkable
412
+ minHeight: 0.5, // below sea level = unwalkable (pair with your Water3D y)
413
+ });
414
+ const cells = findPath(nav.grid, nav.toCell(ex, ez), nav.toCell(px, pz));
415
+ if (cells) follow.setPath(cells.map(([cx, cy]) => nav.toWorld(cx, cy)));
416
+ // nav.toWorld's y IS the terrain height — PathFollow rides the surface.
417
+ ```
418
+
419
+ - Build it ONCE per scene (onReady) — sampling is O(cells); re-pathing with
420
+ `findPath` per second is cheap (binary-heap A*).
421
+ - Trees/rocks/buildings aren't in the heightfield: stamp them out with
422
+ `nav.setSolid(...nav.toCell(x, z))` after building.
423
+ - Walkability is judged inside each cell (corner samples), so a flat trail
424
+ beside a cliff stays walkable — only genuinely steep cells go solid.
425
+
391
426
  ## Performance levers for big scenes
392
427
 
393
428
  - **`static: true`** (any Node3D): the renderer syncs that subtree ONCE and
@@ -119,9 +119,9 @@ active brush. The palette chips offer every char already used in `cells`, the
119
119
  single char (digits map straight to atlas tile indices, other chars need a
120
120
  `legend` entry). The grid grows right/down automatically when you paint past
121
121
  the edge — to grow left/up, move the node instead (cell (0,0) hangs on the
122
- node origin). Merged solid colliders re-derive live as you paint. Each painted
123
- cell is one undo step; toggle paint off (or select another node) to get normal
124
- click-select back.
122
+ node origin). Merged solid colliders re-derive live as you paint. A whole
123
+ drag stroke is ONE undo step; toggle paint off (or select another node) to
124
+ get normal click-select back.
125
125
 
126
126
  ## Generate environments
127
127
 
@@ -173,6 +173,14 @@ const hit = physics.castRay(origin, dir, maxLen, excludeBody?, { staticOnly?: tr
173
173
 
174
174
  Exclude the shooter's own body when casting from inside it.
175
175
 
176
+ 3D also has a THICK ray — a sphere sweep — for probes where skimming matters
177
+ (the camera boom, ledge feelers):
178
+
179
+ ```ts
180
+ const hit = physics.castSphere(origin, dir, radius, maxLen, excludeBody?, { staticOnly?: true });
181
+ // → { distance, node } | null (distance = travel of the sphere CENTER)
182
+ ```
183
+
176
184
  ## Gamepad
177
185
 
178
186
  `engine.input.attachGamepad(engine)` polls the first connected pad every