incanto 0.75.0 → 0.77.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.d.ts +1 -1
- package/dist/2d.js +4 -4
- package/dist/3d.d.ts +121 -3
- package/dist/3d.js +4 -4
- package/dist/{create-game-DnwhJ5nW.js → create-game-BMIPKrQW.js} +5 -5
- package/dist/{create-game-DVUhHs2B.js → create-game-Dai5vfVu.js} +5 -5
- package/dist/{editor-switch-O8mxpgRX.d.ts → editor-switch-Bzt0GzVp.d.ts} +12 -2
- package/dist/{environment-presets-BP77Dl0K.js → environment-presets-e_9YCnGu.js} +348 -36
- package/dist/{gameplay-D-JuGura.js → gameplay-Bfff_beb.js} +1468 -61
- package/dist/gameplay.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{physics-2d-x3bCrQf0.js → physics-2d-Tuf5LAyq.js} +2 -2
- package/dist/{physics-3d-Bz2VPQ6D.js → physics-3d-C5MOujfQ.js} +2 -2
- package/dist/{picking-Buita5T9.js → picking-DIwE48sU.js} +8 -5
- package/dist/react.js +1 -1
- package/dist/{register-DxAbTO2T.js → register-7E3P1gz6.js} +1 -1
- package/dist/{src-DLKVc6Hj.js → src-DygJfhOb.js} +1 -1
- package/dist/{test-HlVUeCSn.js → test-CVbxnXlv.js} +7 -7
- package/dist/test.js +1 -1
- package/dist/vite.d.ts +47 -3
- package/dist/vite.js +81 -20
- package/editor/assets/{agent8-BXlYM9rv.js → agent8-DA-I5qhv.js} +1 -1
- package/editor/assets/{debug-S42XGP4Y.js → debug-99tEPoGm.js} +1 -1
- package/editor/assets/index-Db74LZY-.js +11579 -0
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +30 -2
- package/skills/incanto-3d-character.md +26 -1
- package/skills/incanto-editor.md +56 -2
- package/skills/incanto-environment.md +30 -12
- package/skills/incanto-node-reference.md +6 -1
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/src/game.scene.json +6 -1
- package/templates-app/molehill-2d/package.json +1 -1
- package/templates-app/platformer-2d/package.json +1 -1
- package/templates-app/star-survivor/package.json +1 -1
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/village-quest-3d/package.json +1 -1
- package/editor/assets/index-DgrgUKno.js +0 -11046
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-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-Db74LZY-.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="./assets/GameServer-C56iOUgF.js">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
package/package.json
CHANGED
|
@@ -2529,13 +2529,24 @@
|
|
|
2529
2529
|
"type": "number",
|
|
2530
2530
|
"default": 0.35
|
|
2531
2531
|
},
|
|
2532
|
+
"slopeLimitDeg": {
|
|
2533
|
+
"type": "number",
|
|
2534
|
+
"default": 55
|
|
2535
|
+
},
|
|
2532
2536
|
"swimSpeed": {
|
|
2533
2537
|
"type": "number",
|
|
2534
2538
|
"default": 1.6
|
|
2535
2539
|
},
|
|
2536
2540
|
"swimDepth": {
|
|
2537
|
-
"
|
|
2538
|
-
|
|
2541
|
+
"anyOf": [
|
|
2542
|
+
{
|
|
2543
|
+
"type": "null"
|
|
2544
|
+
},
|
|
2545
|
+
{
|
|
2546
|
+
"type": "number"
|
|
2547
|
+
}
|
|
2548
|
+
],
|
|
2549
|
+
"default": null
|
|
2539
2550
|
},
|
|
2540
2551
|
"diveAction": {
|
|
2541
2552
|
"type": "string",
|
|
@@ -11061,6 +11072,10 @@
|
|
|
11061
11072
|
"type": "number",
|
|
11062
11073
|
"default": 33
|
|
11063
11074
|
},
|
|
11075
|
+
"ssr": {
|
|
11076
|
+
"type": "boolean",
|
|
11077
|
+
"default": true
|
|
11078
|
+
},
|
|
11064
11079
|
"swellSteepness": {
|
|
11065
11080
|
"type": "number",
|
|
11066
11081
|
"default": 0.35
|
|
@@ -11144,6 +11159,19 @@
|
|
|
11144
11159
|
"type": "number",
|
|
11145
11160
|
"default": 0
|
|
11146
11161
|
},
|
|
11162
|
+
"bed": {
|
|
11163
|
+
"type": "string",
|
|
11164
|
+
"description": "A node path: '%UniqueName', '/Absolute/From/Root', or relative to this node ('../Skin').",
|
|
11165
|
+
"default": ""
|
|
11166
|
+
},
|
|
11167
|
+
"wind": {
|
|
11168
|
+
"type": "number",
|
|
11169
|
+
"default": 0
|
|
11170
|
+
},
|
|
11171
|
+
"choppiness": {
|
|
11172
|
+
"type": "number",
|
|
11173
|
+
"default": 0.85
|
|
11174
|
+
},
|
|
11147
11175
|
"preset": {
|
|
11148
11176
|
"type": "string",
|
|
11149
11177
|
"enum": ["custom", "ocean", "pool", "lake", "pond"],
|
|
@@ -108,6 +108,22 @@ measures 0.32 / 1.26 (`jumpCutMultiplier`), a double jump line
|
|
|
108
108
|
(`maxJumps: 2`), and the coyote and buffer windows still measured with a double
|
|
109
109
|
jump declared. It used to give up on both the moment `maxJumps` went above 1.
|
|
110
110
|
|
|
111
|
+
**`slopeLimitDeg` (55) is the steepest ground the character STANDS on**, and
|
|
112
|
+
below it a character does not slide at all — measured, on a hillside, for as
|
|
113
|
+
long as you leave it there. It used to slide down everything: 0.18 m in three
|
|
114
|
+
seconds on a 6.9° slope, 2.87 m on a 27° one, always exactly downhill. The
|
|
115
|
+
cause is the hover spring measuring its clearance STRAIGHT DOWN while the
|
|
116
|
+
clearance that decides whether the capsule touches is measured perpendicular
|
|
117
|
+
to the surface — negative past ~13° — and every rig setting `friction: 0` (the
|
|
118
|
+
right setting: the character rides the spring, so floor friction only brakes
|
|
119
|
+
it) then slid on the contact. So the spring aims perpendicular now, and on
|
|
120
|
+
ground inside the limit the controller cancels downhill drift it was not asked
|
|
121
|
+
for. Steeper than the limit the ground stops being ground — no `grounded`, no
|
|
122
|
+
jump reset — and the body slips off the face, which is what a slope limit means
|
|
123
|
+
everywhere else. 55 is a person; a goat is 80, something on wheels 25, and `90`
|
|
124
|
+
is the old no-limit behaviour. `controller.groundSlopeDeg` reports what it is
|
|
125
|
+
standing on, and `controller.groundNormal` which way that faces.
|
|
126
|
+
|
|
111
127
|
**`stepHeight` steps onto a ledge at the APEX of a jump too.** A fence 1.5 m
|
|
112
128
|
high was climbed by a jump that peaks at 1.3 m: at the apex the fence top sat
|
|
113
129
|
0.2 m above the capsule's bottom, inside `stepHeight` 0.4, and the step-up
|
|
@@ -159,7 +175,7 @@ stood on the bed with the camera underwater and the run clip playing, in every
|
|
|
159
175
|
| prop | default | what it buys |
|
|
160
176
|
|---|---|---|
|
|
161
177
|
| `swimSpeed` | `1.6` | the pace a plain key gives in water (m/s; `sprint` still multiplies, by the ratio it multiplies a run). **`0` turns swimming OFF** — the body sinks to the bed, which is what a drowning pit wants and what every scene got before. |
|
|
162
|
-
| `swimDepth` | `
|
|
178
|
+
| `swimDepth` | `null` | how far the body's ORIGIN rides below the surface. `null` derives it from the capsule so the head rides 15 cm clear and the rest is in the water — which is what treading water looks like, and what a fixed number cannot be for every character size. (It used to default to a flat `0.35`, and on the 1.68 m capsule every template ships that put the head 0.46 m clear: the character floated along on top like a boat.) A number still wins. |
|
|
163
179
|
| `diveAction` | `"dive"` | held: swim DOWN at `swimSpeed`. Not in the input map = no diving, silently. |
|
|
164
180
|
|
|
165
181
|
- **When.** The body swims when floating would put it HIGHER than standing:
|
|
@@ -455,6 +471,15 @@ controller.on('movementStateChanged', (state) => {
|
|
|
455
471
|
Setting `animation` to a new clip **crossfades** (0.2s blend) from the current
|
|
456
472
|
one — idle↔walk↔run↔jump transitions are smooth, not a hard cut.
|
|
457
473
|
|
|
474
|
+
**A state your map does not name falls back — it never leaves the last clip
|
|
475
|
+
playing.** `swim → walk → idle`, `dash → fastRun → run → walk → idle`,
|
|
476
|
+
`sneak`/`climb → walk → idle`, `crouch`/`airborne → idle`. Every chain ends at
|
|
477
|
+
`idle`, so a map with one clip in it still animates. Without this, a scene that
|
|
478
|
+
mapped only the original five (which is every scene there was) put a swimmer
|
|
479
|
+
across the bay in a frozen JUMP pose, and did the same for `dash`, `climb`,
|
|
480
|
+
`sneak` and `crouch`. Map the state itself when you have the clip: the shipped
|
|
481
|
+
water templates now declare `swim` (`mixamorig/swim.glb` on the agent8 CDN).
|
|
482
|
+
|
|
458
483
|
## Reskin one model with `tint` (many variants from one GLB)
|
|
459
484
|
|
|
460
485
|
`ModelInstance3D` has a `tint` prop (hex, `""` = off) that MULTIPLIES into every
|
package/skills/incanto-editor.md
CHANGED
|
@@ -389,8 +389,10 @@ transport instead. With neither, the buttons are simply absent.
|
|
|
389
389
|
|
|
390
390
|
From that game, the ☰ debug menu's **✎ edit this scene** switches straight back
|
|
391
391
|
to the editor — same window, no reload, and the edit camera picks up the pose
|
|
392
|
-
the player was looking from. **✕ exit**
|
|
393
|
-
|
|
392
|
+
the player was looking from. **✕ exit** returns to the game WITH the scene as
|
|
393
|
+
the editor has it — you were editing it, and half the time you saved it, so
|
|
394
|
+
handing back the json the page booted with would show you your own edit
|
|
395
|
+
disappearing on the way out. The pair is one loop you can ride all session:
|
|
394
396
|
|
|
395
397
|
```
|
|
396
398
|
game --(☰ debug ▸ ✎ edit this scene)--> editor
|
|
@@ -403,6 +405,14 @@ editing wherever the simulation happened to be. Games hosting the editor
|
|
|
403
405
|
themselves (`createGame3D({ editor: … })`) get a **save** button only when they
|
|
404
406
|
pass `editor.save` — otherwise edits live as long as the session does.
|
|
405
407
|
|
|
408
|
+
**Saving keeps you in the editor.** It used to throw you out of it: the save
|
|
409
|
+
writes the scene through `incantoScenes()`'s `PUT /api/scene`, vite saw its own
|
|
410
|
+
watched file change, and a JSON module imported by `main.ts` cannot be
|
|
411
|
+
hot-swapped — so vite full-page-RELOADED, the page came back as the game, and
|
|
412
|
+
the selection, the camera and the panel you were working in were gone. The
|
|
413
|
+
plugin now recognises a write it just made and lets the page be. A hand edit in
|
|
414
|
+
a text editor is news the page does not have, and still reloads.
|
|
415
|
+
|
|
406
416
|
**The handle you booted with does not survive the round trip.** ▶ builds a NEW
|
|
407
417
|
game, so after one ✎→▶ the `game` your app is holding refers to something that
|
|
408
418
|
no longer exists. It is inert rather than destructive — a stale `dispose()` and
|
|
@@ -483,6 +493,50 @@ embedded editor posts nothing. The page posts to its parent window:
|
|
|
483
493
|
{ type: 'incanto-editor:error', message } // loader/save errors
|
|
484
494
|
```
|
|
485
495
|
|
|
496
|
+
### Hearing a save from OUTSIDE the browser
|
|
497
|
+
|
|
498
|
+
A preview running in a container saves into that container, and the process
|
|
499
|
+
supervising it — the one that rebuilds, commits or syncs — is not in the page.
|
|
500
|
+
It has two ways to hear about it, and neither needs the iframe:
|
|
501
|
+
|
|
502
|
+
**1. stdout, zero configuration.** Every scene this dev server writes announces
|
|
503
|
+
itself on the terminal you are already tailing, as ONE line: a fixed `[incanto] `
|
|
504
|
+
prefix and a JSON object.
|
|
505
|
+
|
|
506
|
+
```
|
|
507
|
+
[incanto] {"event":"scene:saved","file":"src/game.scene.json","bytes":13284,"at":"2026-09-08T10:19:57.412Z"}
|
|
508
|
+
[incanto] {"event":"scene:created","file":"src/levels/arena.scene.json","bytes":214,"at":"…"}
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
`file` is project-relative with forward slashes on every OS, `bytes` is what was
|
|
512
|
+
written, `at` is ISO-8601. The line is printed only when the bytes LANDED — a
|
|
513
|
+
refused write (not a scene, would overwrite a non-scene) says nothing, so the
|
|
514
|
+
line means "there is something new on disk". Read the fields you know and ignore
|
|
515
|
+
the rest: more may be added, these will not change. Nothing to configure; a
|
|
516
|
+
project with `incantoScenes()` in its vite config already prints it.
|
|
517
|
+
|
|
518
|
+
Do not scrape vite's own `page reload <file>` line for this. It appears for a
|
|
519
|
+
HAND edit and deliberately does not for the editor's own save (that reload used
|
|
520
|
+
to throw you out of the editor mid-edit).
|
|
521
|
+
|
|
522
|
+
**2. `onSave`, in-process, with the scene itself.** When the host wants the JSON
|
|
523
|
+
rather than the path:
|
|
524
|
+
|
|
525
|
+
```ts
|
|
526
|
+
incantoScenes({
|
|
527
|
+
onSave: ({ event, file, abs, json }) => {
|
|
528
|
+
// event: 'scene:saved' | 'scene:created'
|
|
529
|
+
void fetch('http://127.0.0.1:9000/scene-saved', {
|
|
530
|
+
method: 'POST',
|
|
531
|
+
body: JSON.stringify({ file, json }),
|
|
532
|
+
});
|
|
533
|
+
},
|
|
534
|
+
})
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
It runs after the write, and a throw from it is reported and swallowed — a
|
|
538
|
+
broken hook must not take the dev server down or silence the stdout line.
|
|
539
|
+
|
|
486
540
|
The page can never choose filesystem paths — `input`/`output` are fixed at launch;
|
|
487
541
|
the API only reads the input and writes the output. Saves are rejected (422, file
|
|
488
542
|
untouched) unless the body is scene-shaped (`format: 1`, `type: "scene"`, `name`,
|
|
@@ -907,15 +907,29 @@ A commercial-quality water surface (in `incanto/3d`, registered by
|
|
|
907
907
|
`examples/water-*-3d` templates stage one each (cove pier, resort pool,
|
|
908
908
|
mirror-lake dock, walled garden pond). The default `quality: 'fancy'` is a
|
|
909
909
|
real water shader:
|
|
910
|
-
9-iteration simplex-FBM wave displacement with analytic normals,
|
|
910
|
+
9-iteration simplex-FBM wave displacement with analytic normals — or, with
|
|
911
|
+
`wind` > 0, a real JONSWAP SPECTRUM inverse-FFT'd on the GPU every frame (the
|
|
912
|
+
ocean preset: 65 536 waves, each at its own deep-water speed, choppy crests,
|
|
913
|
+
whitecaps where the surface folds, and a per-pixel slope texture whose mips
|
|
914
|
+
hand a far pixel the slope VARIANCE it integrates — the roughness of a distant
|
|
915
|
+
sea, measured rather than guessed) — plus optional
|
|
911
916
|
DIRECTIONAL TRAVELING SWELL trains + open-water whitecaps (`swell` /
|
|
912
917
|
`whitecaps` — the open-ocean look; see the prop table), a DISPERSION-TIMED
|
|
913
918
|
micro-ripple spectrum — four octaves (λ 6 m → 0.38 m), each advected at its
|
|
914
919
|
REAL deep-water phase speed so short ripples flicker ~2×/s (slow fine ripple
|
|
915
920
|
is what makes water read as syrup), the fine octaves interference-PAIRED so
|
|
916
|
-
the surface churns instead of sliding, each octave distance-faded
|
|
917
|
-
|
|
918
|
-
|
|
921
|
+
the surface churns instead of sliding, each octave distance-faded, plus a
|
|
922
|
+
16 cm "spark" octave inside arm's reach — the SUN as a real GGX microfacet
|
|
923
|
+
highlight off that spectrum (near the camera every resolved facet
|
|
924
|
+
that faces the sun flashes, HDR so the bloom pass reads it; with distance
|
|
925
|
+
the roughness grows and the same lobe widens into the continuous sun path a
|
|
926
|
+
far sea shows — no azimuth gate, no hand-shaped powers), a SEA-STATE
|
|
927
|
+
fresnel (the far, wind-roughened field reflects the sky at the ~0.5-0.6 a
|
|
928
|
+
rough mirror really does at grazing angles, so the ocean stays a darker band
|
|
929
|
+
under its sky instead of whiting out into the horizon haze; calm near water
|
|
930
|
+
is untouched), light THROUGH the crest (with `swell`: looking toward the sun
|
|
931
|
+
the thin crests glow translucent turquoise — lit from inside, the one cue
|
|
932
|
+
that says water rather than painted lumps), per-channel
|
|
919
933
|
Beer's-law depth `absorption` (red dies first — turquoise shallows fade
|
|
920
934
|
WIDE into deep teal-blue, like a real sea), CRYSTAL shallows (inside the
|
|
921
935
|
first ~1.5 m of water the refracted bottom dominates, ripple-distorted —
|
|
@@ -960,24 +974,28 @@ hue reads grey.
|
|
|
960
974
|
| `reflection` | `true` | live CubeCamera reflections (fancy only; needs a renderer) |
|
|
961
975
|
| `reflectionInterval` | `1000` | ms between CubeCamera reflection re-renders |
|
|
962
976
|
| `mirror` | `false` | TRUE planar reflection (see below) — the only way the dock, the boat and the player appear IN the water. One extra scene render per frame |
|
|
977
|
+
| `ssr` | `true` | screen-space reflections (fancy only): the scene ABOVE the waterline is rendered once at half res and every water pixel marches its reflected ray through that image — a rock, a pier, a wader, a boat mirrored on the water with NO planar pass. What the screen cannot see (behind the camera, past its edges) falls back to the sky cube, so a mirror-calm lake still wants `mirror: true`; with `mirror` on this is skipped as redundant, and a tier that forbids the mirror pass forbids this too (same cost class: one more half-res scene submission). `false` keeps the cube-only sky reflection |
|
|
963
978
|
| `mirrorInterval` | `33` | ms between planar-mirror re-renders. A reflection seen through a rippling surface does not need 60 Hz; 33 halves the pass's cost. 0 = every frame |
|
|
964
979
|
| `swellSteepness` | `0.35` | GERSTNER pinch on the swell: 0 = height-only trains, 1 = maximum trochoid (crests narrow to a peak, troughs broaden). It also decides where whitecaps break — the surface's Jacobian collapses on a folding crest, and that is where foam belongs |
|
|
965
980
|
| `foam` | `true` | noise-broken shoreline foam band + crest foam near shores |
|
|
966
981
|
| `interaction` | `true` | character interaction: bodies (CharacterBody3D/RigidBody3D) inside the XZ footprint whose FEET dip below the surface count as in-water — so a WADING character (origin above water, feet below, sized from its collider) splashes, not only a fully-submerged one. Entry/exit emit `entered`/`exited` + a splash ripple; striding through water trails a WAKE (a ripple every ~0.45 m); floating bodies bob gently. Ripples drive both shaders' `uRipples[8]` (fancy) and CPU-displace the mesh (`simple`) |
|
|
967
982
|
| `splash` | `true` | built-in splash WHITEWATER (needs `interaction`): the shaders paint expanding **surface foam** where bodies interact — a **"풍덩"** froth bloom when a body plunges in (bigger the faster it falls) and a **foam trail ("물살")** behind a body wading/running through. Real frothy whitewater on the surface, not flying droplets; works on both `fancy` and `simple` quality. `false` keeps the ripples/waves but paints no foam. No wiring needed; for an extra custom burst add your own `Particles3D` on the `entered` signal |
|
|
968
983
|
| `sunDirection` | `[0.5, 0.8, 0.3]` | TOWARD the sun, for the specular glint — match the scene's key light (non-zero, load-time check) |
|
|
969
|
-
| `sunColor` | `"#fff5d6"` |
|
|
970
|
-
| `sunIntensity` | `1` |
|
|
971
|
-
| `detailStrength` | `0.26` | animated detail-normal strength (≥ 0; 0 = vertex normals only) |
|
|
984
|
+
| `sunColor` | `"#fff5d6"` | sun highlight tint |
|
|
985
|
+
| `sunIntensity` | `1` | sun highlight strength (≥ 0; 0 = off). The highlight is a GGX lobe over the detail normal and runs HDR on purpose — the sun's reflection is the brightest thing on any water and is what `environment.bloom` catches; 0.7-1.25 is the presets' range |
|
|
986
|
+
| `detailStrength` | `0.26` | animated detail-normal strength (≥ 0; 0 = vertex normals only). Under it runs a LIVE ripple FFT (a second 6 m spectrum patch, 4.7 cm texels, inverse-transformed every frame): the wind ripple every fancy surface wears — real churn with a mip chain for distance instead of scrolling noise — normalized so its rms slope is 0.8 × this value; three short procedural octaves stay on at reduced weight for the sub-pixel facets that flash (a filtered texture alone hands the sun one soft lobe). Without float render targets the noise octaves carry it all, as before |
|
|
972
987
|
| `absorption` | `0.15` | Beer's-law constant per meter of water depth (≥ 0; lower = clearer/wider turquoise band; red absorbs ~3× faster than blue under the hood) |
|
|
973
988
|
| `refraction` | `true` | screen-space refraction of the submerged scene |
|
|
974
|
-
| `preset` | `"custom"` | **THE one-choice water type** (0.16.0): `ocean` \| `pool` \| `lake` \| `pond` bundles every wave/color/clarity/caustics knob into a hand-tuned sea state. A preset value applies ONLY where a prop still sits at its schema default — pick the type, then override any detail prop and your value wins. ocean = traveling swell + whitecaps + wide turquoise→deep absorption · pool = near-flat crystal water + strong above-water caustics · lake = calm high-reflectivity mirror, green-teal murk · pond = still, mossy, opaque quickly. `custom` (default) changes nothing |
|
|
989
|
+
| `preset` | `"custom"` | **THE one-choice water type** (0.16.0): `ocean` \| `pool` \| `lake` \| `pond` bundles every wave/color/clarity/caustics knob into a hand-tuned sea state. A preset value applies ONLY where a prop still sits at its schema default — pick the type, then override any detail prop and your value wins. ocean = traveling swell + whitecaps + wide turquoise→deep absorption · pool = near-flat crystal water + strong above-water caustics · lake = calm high-reflectivity mirror, green-teal murk, short low wind chop (a 9 m set at 3 cm — a lake has no swell, and the 24 m one it used to ship was the single strongest source of the 꿀렁꿀렁 gel read) · pond = still, mossy, opaque quickly. `custom` (default) changes nothing |
|
|
975
990
|
| `shoreWaves` | `0` | **traveling shore BREAKERS** 0–1 (fancy + depth pre-pass, 0.17.0): foam fronts that roll down the depth gradient and break toward every beach — fronts follow the shore's depth contours automatically (bays curve them, points wrap them, zero wiring). Sharp collapsing face + long noisy wash, alive in the 0.1–3.2 m shoaling band. Ocean preset ships 0.7 |
|
|
976
991
|
| `causticsAbove` | `0` | above-water CAUSTICS intensity 0–3 (fancy + `refraction` only): the dancing light web on the submerged bottom seen THROUGH the surface — the pool / tropical-shallows look. Reconstructed on the real refracted bottom position, strongest through the first meters of water, distance-faded. Presets set it (pool 1.0); override freely |
|
|
977
992
|
| `swell` | `0` | **THE open-ocean dial** (fancy only, 0.15.0): directional traveling swell amplitude in meters. Three peaked wave trains (primary + two crossing sets) march across the surface at real deep-water speeds; crests light up toward the peak color and wave FACES get sun-lit/shadow shading, so the swell reads at any distance. 0.15 = lively lake chop, 0.4 = coastal sea, 0.7 = heavy weather. `0` (default) keeps the legacy calm look byte-identical |
|
|
978
993
|
| `swellDirectionDeg` | `0` | compass direction the swell TRAVELS toward (0 = +z, 90 = +x) |
|
|
979
994
|
| `swellWavelength` | `30` | primary swell wavelength, meters (≥ 2, load-time check); the crossing trains derive from it |
|
|
980
|
-
| `whitecaps` | `0` | open-water whitecap foam on the tallest crests, 0–1 (fancy only; load-time check). Pairs with `swell` — the caps ride its crest lines and fade with distance so the horizon stays clean |
|
|
995
|
+
| `whitecaps` | `0` | open-water whitecap foam on the tallest crests, 0–1 (fancy only; load-time check). Pairs with `swell` — the caps ride its crest lines and fade with distance so the horizon stays clean. With `wind` on, the caps are born where the FFT sea's surface actually FOLDS (its Jacobian) and fade over seconds |
|
|
996
|
+
| `bed` | `""` | node path to the Terrain3D under this water (fancy only). With it the swell KNOWS the beach: once the water is shallower than a quarter wavelength a wave RISES by Green's law (depth^-1/4, capped 2×) and its crest peaks; at 0.78× the depth it BREAKS — the height is capped there and the crest turns to torn whitewater — and the FFT sea shoals and breaks the same way. Spray sprites burst on the 0.3–0.9 m break line when the `shoreWaves` foam fronts pass (needs `shoreWaves` > 0; a few hundred camera-facing puffs, one draw). Sampled once into a 256² depth grid over the terrain's footprint; beyond it the water is assumed 12 m deep. The ocean template points it at its island |
|
|
997
|
+
| `wind` | `0` | **THE realistic-sea dial** (fancy only; m/s; ≥ 0, load-time check). Above 0 the surface stops being a noise field and becomes a JONSWAP SPECTRUM — thousands of waves at every wavelength and heading, each moving at the speed deep water gives it — inverse-FFT'd on the GPU every frame (256², ~37 tiny passes) into a 200 m tiling patch with real crest shapes, choppy horizontal drag and fold-born whitecaps. Blows toward `swellDirectionDeg`. 4 = a light breeze (20 cm ripple), 6.5 = the ocean preset's fresh breeze (Hs ≈ 1.4 m), 12 = rough. `waveHeight` is inert while wind > 0 (the FBM is replaced, not added); `swell` still rides underneath as the long-period set a 200 m patch cannot hold. `heightAt` / buoyancy / waders sum the strongest 2048 modes of the SAME spectrum on the CPU (~8% of the rms height, ~45 µs a call). Needs float render targets (every WebGL2 desktop, iOS 15+) — without them the analytic waves stay and the CPU twin follows |
|
|
998
|
+
| `choppiness` | `0.85` | horizontal drag of the FFT sea toward its crests (≥ 0): 0 = pure height field, ~0.9 = narrow crests over broad troughs, past ~1.2 the surface folds and foams everywhere |
|
|
981
999
|
| `underwater` | `true` | submerged-camera look: ONLY when the camera EYE is below this surface (inside its XZ footprint) — wading with the camera above the water never tints the view — the scene switches to short-range underwater fog + tint, the sky is hidden, and animated **caustics** (depth-aware, projected onto the submerged floor/props) play. `false` disables it; an object `{ color?, visibility?, caustics? }` overrides the murk hue / view distance (m, default 22) / caustics. `caustics` is `true` (default) \| `false` \| `{ color?, intensity?, scale?, speed? }`. The murk color defaults to a darkened shade of `color`. Works for both qualities (the caustics composite runs only while the camera is genuinely underwater) |
|
|
982
1000
|
|
|
983
1001
|
Performance notes (fancy): beyond drawing the surface, each rendered frame
|
|
@@ -1317,16 +1335,16 @@ underneath decides everything else.
|
|
|
1317
1335
|
| `widths` | `[]` | width profile lerped source→mouth (e.g. `[2.5, 5, 9]`); empty = constant `width` |
|
|
1318
1336
|
| `depth` | `0.8` | water column at the centerline — also the scale foam thresholds read as "shallow" |
|
|
1319
1337
|
| `flowSpeed` | `1.6` | reference current in m/s (the mean; reaches speed up and slow down) |
|
|
1320
|
-
| `colors` | `{}` | `{ shallow, deep, sky, horizon, bank }` — the body ramp plus what the surface mirrors |
|
|
1338
|
+
| `colors` | `{}` | `{ shallow, deep, sky, horizon, bank }` — the body ramp plus what the surface mirrors. In a live renderer the river keeps its OWN sky cube (the world beyond its banks, refreshed every 2 s, near-clipped so the banks never smear across it) and mirrors THAT through a sea-state fresnel; `sky`/`horizon` are then the headless fallback and `bank` is still what the lowest rays meet. A 6 m ripple FFT rides the current in the ribbon's own frame under `ripples` |
|
|
1321
1339
|
| `absorption` | `0.5` | how fast the water hides its bed (Beer's law) |
|
|
1322
1340
|
| `opacity` | `0.85` | upper bound on the body's opacity |
|
|
1323
1341
|
| `foam` | `1` | whitewater dial — 0 = a glassy canal, 2 = raging |
|
|
1324
|
-
| `ripples` | `1` | surface-detail dial (ripple relief
|
|
1342
|
+
| `ripples` | `1` | surface-detail dial (ripple relief, the fine near-field wavelets, and how much sun the water throws) |
|
|
1325
1343
|
| `terrain` | `""` | drape target path; empty = auto-find the first Terrain3D (a wrong path fails at load) |
|
|
1326
1344
|
| `carve` | `true` | cut the bed. The river trenches its own channel into the terrain it drapes on — see below |
|
|
1327
1345
|
| `flowForce` | `1` | how hard the current sweeps bodies downstream (0 = visual only) |
|
|
1328
1346
|
| `spray` | `1` | mist at the foot of every drop the course turns out to contain — the node finds them and hangs a Particles3D plume on each (0 = off) |
|
|
1329
|
-
| `sunDirection` / `sunColor` / `sunIntensity` | sky / `#fff6e0` / `1` |
|
|
1347
|
+
| `sunDirection` / `sunColor` / `sunIntensity` | sky / `#fff6e0` / `1` | the sun highlight — a GGX lobe over the wavelet normal, HDR so the bloom pass reads it (the environment sun wins while `sunDirection` is default) |
|
|
1330
1348
|
|
|
1331
1349
|
**What the node derives for you**, all from `path` + the ground:
|
|
1332
1350
|
|
|
@@ -338,8 +338,9 @@ Signals: `movementStateChanged(state)`
|
|
|
338
338
|
| `fallGravity` | `2.5` | number |
|
|
339
339
|
| `floatHeight` | `0.01` | number |
|
|
340
340
|
| `stepHeight` | `0.35` | number |
|
|
341
|
+
| `slopeLimitDeg` | `55` | number |
|
|
341
342
|
| `swimSpeed` | `1.6` | number |
|
|
342
|
-
| `swimDepth` | `
|
|
343
|
+
| `swimDepth` | `null` | any JSON — see the skill for the accepted shapes, or number |
|
|
343
344
|
| `diveAction` | `"dive"` | string |
|
|
344
345
|
| `climbSpeed` | `1.5` | number |
|
|
345
346
|
| `ladderGroup` | `"ladder"` | string |
|
|
@@ -1632,6 +1633,7 @@ Methods: `blockCount()` · `tileAt(x, y, z)` · `setBlocks(blocks)` · `addBlock
|
|
|
1632
1633
|
| `reflectionInterval` | `1000` | number |
|
|
1633
1634
|
| `mirror` | `false` | boolean |
|
|
1634
1635
|
| `mirrorInterval` | `33` | number |
|
|
1636
|
+
| `ssr` | `true` | boolean |
|
|
1635
1637
|
| `swellSteepness` | `0.35` | number |
|
|
1636
1638
|
| `foam` | `true` | boolean |
|
|
1637
1639
|
| `reflectivity` | `null` | any JSON — see the skill for the accepted shapes, or number |
|
|
@@ -1648,6 +1650,9 @@ Methods: `blockCount()` · `tileAt(x, y, z)` · `setBlocks(blocks)` · `addBlock
|
|
|
1648
1650
|
| `swellDirectionDeg` | `0` | number |
|
|
1649
1651
|
| `swellWavelength` | `30` | number |
|
|
1650
1652
|
| `whitecaps` | `0` | number |
|
|
1653
|
+
| `bed` | `""` | node path |
|
|
1654
|
+
| `wind` | `0` | number |
|
|
1655
|
+
| `choppiness` | `0.85` | number |
|
|
1651
1656
|
| `preset` | `"custom"` | one of: `custom` `ocean` `pool` `lake` `pond` |
|
|
1652
1657
|
| `causticsAbove` | `0` | number |
|
|
1653
1658
|
| `shoreWaves` | `0` | number |
|
|
@@ -66,6 +66,10 @@
|
|
|
66
66
|
"anims/attack": {
|
|
67
67
|
"type": "animation",
|
|
68
68
|
"url": "https://agent8-games.verse8.io/assets/3d/animations/mixamorig/melee-attack.glb"
|
|
69
|
+
},
|
|
70
|
+
"anims/swim": {
|
|
71
|
+
"type": "animation",
|
|
72
|
+
"url": "https://agent8-games.verse8.io/assets/3d/animations/mixamorig/swim.glb"
|
|
69
73
|
}
|
|
70
74
|
},
|
|
71
75
|
"root": {
|
|
@@ -2460,7 +2464,8 @@
|
|
|
2460
2464
|
"walk": "$anims/walk",
|
|
2461
2465
|
"run": "$anims/run",
|
|
2462
2466
|
"fastRun": "$anims/runFast",
|
|
2463
|
-
"airborne": "$anims/jump"
|
|
2467
|
+
"airborne": "$anims/jump",
|
|
2468
|
+
"swim": "$anims/swim"
|
|
2464
2469
|
}
|
|
2465
2470
|
},
|
|
2466
2471
|
"script": { "name": "SwordStrike" },
|