incanto 0.45.1 → 0.47.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.
Files changed (38) hide show
  1. package/bin/incanto-check.mjs +5 -1
  2. package/bin/incanto-feel.mjs +5 -1
  3. package/bin/incanto-frame.mjs +57 -6
  4. package/bin/incanto-model.mjs +79 -10
  5. package/bin/incanto-playtest.mjs +5 -1
  6. package/bin/incanto-verify.mjs +214 -0
  7. package/dist/2d.d.ts +1 -1
  8. package/dist/2d.js +1 -1
  9. package/dist/3d.d.ts +90 -5
  10. package/dist/3d.js +92 -5
  11. package/dist/{create-game-DFRbG0Bj.js → create-game-CniOiWzN.js} +1 -1
  12. package/dist/{create-game-Gifrjhnz.js → create-game-D16MVIPO.js} +24 -5
  13. package/dist/{editor-switch-DVwIGZdK.d.ts → editor-switch-DAvWQeld.d.ts} +1 -1
  14. package/dist/editor.js +4674 -4346
  15. package/dist/{environment-presets-DUsBqvtk.js → environment-presets-D1b0ydTS.js} +5 -4
  16. package/dist/{frame-report-Ct8XgsmV.d.ts → frame-report-DZ70IY26.d.ts} +25 -0
  17. package/dist/{frame-report-Lr3VO24R.js → frame-report-njybhZon.js} +130 -3
  18. package/dist/index.js +1 -1
  19. package/dist/{physics-3d-DFqMtBUD.js → physics-3d-CSoGjM8P.js} +1 -1
  20. package/dist/react.js +1 -1
  21. package/dist/{src-DUxGnvq3.js → src-Ca3oV1fe.js} +1 -1
  22. package/dist/{teardown-yePMOE1K.js → teardown-BKTCzLek.js} +3 -2
  23. package/dist/{test-DD5scWfm.js → test-E4-otKqK.js} +54 -7
  24. package/dist/test.d.ts +55 -1
  25. package/dist/test.js +2 -2
  26. package/dist/vite.d.ts +34 -3
  27. package/dist/vite.js +104 -12
  28. package/editor/assets/{agent8-B25qJ5Wo.js → agent8-_007gPF8.js} +1 -1
  29. package/editor/assets/{debug-CUsz-pT8.js → debug-0DI_MJaq.js} +1 -1
  30. package/editor/assets/{index-3u3GVteP.js → index-B-6eYZEi.js} +173 -96
  31. package/editor/index.html +1 -1
  32. package/package.json +3 -2
  33. package/skills/incanto-3d-models.md +30 -0
  34. package/skills/incanto-editor.md +6 -1
  35. package/skills/incanto-verifying-your-game.md +60 -1
  36. package/templates-app/beacon-isle-3d/package.json +1 -1
  37. package/templates-app/tps-3d/package.json +1 -1
  38. package/templates-app/village-quest-3d/package.json +1 -1
package/dist/3d.js CHANGED
@@ -1,9 +1,96 @@
1
1
  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-BQOeAid6.js";
2
- import { A as Terrain3D, B as keyboardIntensity, C as resolveFlowerDensity, D as BoneLookAt3D, E as Camera3D, F as InstancedMesh3D, G as acquireTexture, H as rigPose, I as MeshInstance3D, M as TERRAIN_THEMES, N as terrainThemeLayers, O as BoneAttachment3D, P as Joint3D, R as QUARTER_PITCH, S as Flowers3D, T as CharacterController3D, U as TextureCache3D, V as movementState, W as acquireOwnTexture, _ as LoftMesh3D, a as Tree3D, b as Foliage3D, c as buildRiverRings, d as riverCarveChannels, f as riverStepFor, g as ModelInstance3D, h as Particles3D, i as VoxelGrid3D, j as DEFAULT_TERRAIN_TEXTURE_BASE, k as Billboard3D, l as findRiverCoverageGaps, m as traceDownhillPath, n as registerNodes3D, o as Trail3D, p as smoothCourse, r as VOXEL_PALETTE, s as River3D, u as projectToRiver, v as DirectionalLight3D, w as FLOWER_VARIETIES, x as DENSITY_PRESETS, y as OmniLight3D, z as cameraRelative } from "./environment-presets-DUsBqvtk.js";
3
- import { a as Environment3D, c as parseEnvironment3D, d as AssetStore3D, i as syncTree, l as sunDirectionFromElevationAzimuth, o as setEnvironment3D, r as Renderer3D, s as horizonColorFromSky, t as createGame3D, u as sunDirectionFromSky } from "./create-game-Gifrjhnz.js";
4
- import { a as frameStats, i as frameSignature, n as diffSignatures, o as frameText, r as diffText, t as SIGNATURE_GRID } from "./frame-report-Lr3VO24R.js";
2
+ import { A as Terrain3D, B as keyboardIntensity, C as resolveFlowerDensity, D as BoneLookAt3D, E as Camera3D, F as InstancedMesh3D, G as acquireTexture, H as rigPose, I as MeshInstance3D, M as TERRAIN_THEMES, N as terrainThemeLayers, O as BoneAttachment3D, P as Joint3D, R as QUARTER_PITCH, S as Flowers3D, T as CharacterController3D, U as TextureCache3D, V as movementState, W as acquireOwnTexture, _ as LoftMesh3D, a as Tree3D, b as Foliage3D, c as buildRiverRings, d as riverCarveChannels, f as riverStepFor, g as ModelInstance3D, h as Particles3D, i as VoxelGrid3D, j as DEFAULT_TERRAIN_TEXTURE_BASE, k as Billboard3D, l as findRiverCoverageGaps, m as traceDownhillPath, n as registerNodes3D, o as Trail3D, p as smoothCourse, r as VOXEL_PALETTE, s as River3D, u as projectToRiver, v as DirectionalLight3D, w as FLOWER_VARIETIES, x as DENSITY_PRESETS, y as OmniLight3D, z as cameraRelative } from "./environment-presets-D1b0ydTS.js";
3
+ import { a as Environment3D, c as parseEnvironment3D, d as AssetStore3D, i as syncTree, l as sunDirectionFromElevationAzimuth, o as setEnvironment3D, r as Renderer3D, s as horizonColorFromSky, t as createGame3D, u as sunDirectionFromSky } from "./create-game-D16MVIPO.js";
4
+ import { a as frameSignature, n as diffSignatures, o as frameStats, r as diffText, s as frameText, t as SIGNATURE_GRID } from "./frame-report-njybhZon.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-DFqMtBUD.js";
6
+ import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-CSoGjM8P.js";
7
+ //#region src/3d/model-verdict.ts
8
+ /** Mixamo exports every bone as `mixamorigX`; the retargeter binds by that name. */
9
+ const MIXAMO = /^mixamorig[:_]?/i;
10
+ /**
11
+ * Anything outside this is not a character at this scale, and the fix is one
12
+ * prop. Wide on purpose: a 2.4m ogre is a design choice, a 40m one is
13
+ * centimetres.
14
+ */
15
+ const CHARACTER_HEIGHT = {
16
+ min: .4,
17
+ max: 4
18
+ };
19
+ /** What `targetHeight` gets set to when a model is plainly the wrong scale. */
20
+ const DEFAULT_TARGET_HEIGHT = 1.7;
21
+ /** Fraction of the model's own height that its origin may drift before it matters. */
22
+ const ORIGIN_TOLERANCE = .25;
23
+ function rigOf(facts) {
24
+ if (facts.vrm && facts.vrm.humanBones > 0) return "vrm-humanoid";
25
+ if (facts.nodes.some((n) => MIXAMO.test(n.name))) return "mixamorig";
26
+ return facts.skins > 0 ? "other" : "none";
27
+ }
28
+ function modelVerdict(facts, target) {
29
+ const rig = rigOf(facts);
30
+ const kind = facts.meshes === 0 && facts.animations.length > 0 ? "animation" : "model";
31
+ const height = facts.bbox ? facts.bbox.size[1] : 0;
32
+ const offset = facts.bbox ? [
33
+ facts.bbox.center[0],
34
+ facts.bbox.min[1],
35
+ facts.bbox.center[2]
36
+ ] : [
37
+ 0,
38
+ 0,
39
+ 0
40
+ ];
41
+ const slack = Math.max(height * ORIGIN_TOLERANCE, .05);
42
+ const grounded = !facts.bbox || Math.abs(offset[0]) <= slack && Math.abs(offset[1]) <= slack && Math.abs(offset[2]) <= slack;
43
+ const oddSize = height > 0 && (height < CHARACTER_HEIGHT.min || height > CHARACTER_HEIGHT.max);
44
+ const props = { model: `$${target?.key ?? "model"}` };
45
+ if (oddSize) props.targetHeight = DEFAULT_TARGET_HEIGHT;
46
+ return {
47
+ kind,
48
+ rig,
49
+ takesLibraryClips: kind === "model" && (rig === "mixamorig" || rig === "vrm-humanoid"),
50
+ height,
51
+ originOffset: offset,
52
+ groundedAtOrigin: grounded,
53
+ embeddedClips: facts.animations.map((a) => a.name),
54
+ sceneJson: target ? {
55
+ assets: { [target.key]: {
56
+ type: kind,
57
+ url: target.url
58
+ } },
59
+ node: kind === "animation" ? null : {
60
+ name: titleCase(target.key),
61
+ type: "ModelInstance3D",
62
+ props
63
+ }
64
+ } : null
65
+ };
66
+ }
67
+ const titleCase = (key) => key.split(/[-_\s]+/).filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("") || "Model";
68
+ const round = (n) => String(Math.round(n * 100) / 100);
69
+ /** The verdict as sentences: what to do, and what will bite if you do not. */
70
+ function verdictText(v) {
71
+ const lines = [];
72
+ if (v.kind === "animation") {
73
+ lines.push("an animation CLIP — no mesh of its own. It plays ON a character: declare it as {\"type\":\"animation\"} and point a ModelInstance3D's `animation` at it. Used as a `model` it draws nothing at all, with no error");
74
+ if (v.embeddedClips.length > 0) lines.push(`clip: ${v.embeddedClips.join(", ")}`);
75
+ return lines.join("\n");
76
+ }
77
+ if (v.rig === "mixamorig") lines.push("mixamorig rig — the 3d/animations clips play on this as they are");
78
+ else if (v.rig === "vrm-humanoid") lines.push("VRM humanoid — clips are retargeted onto it automatically");
79
+ else if (v.rig === "other") lines.push("skinned, but NOT a mixamorig rig — the 3d/animations clips will not bind to it (bones are matched by name; a mismatch keeps the bind pose and only warns)");
80
+ else lines.push("no skeleton — a prop, not a character; `animation` does nothing here");
81
+ if (v.height > 0) {
82
+ const odd = v.height < CHARACTER_HEIGHT.min || v.height > CHARACTER_HEIGHT.max;
83
+ lines.push(`stands ${round(v.height)} units tall` + (odd ? ` — not a character's size; set targetHeight (${DEFAULT_TARGET_HEIGHT}) to fix it` : ""));
84
+ }
85
+ if (!v.groundedAtOrigin) {
86
+ const [x, y, z] = v.originOffset;
87
+ const where = Math.abs(y) > Math.abs(x) && Math.abs(y) > Math.abs(z) ? `${round(Math.abs(y))} units ${y > 0 ? "above" : "below"} the origin` : `off-centre by [${round(x)}, ${round(y)}, ${round(z)}]`;
88
+ lines.push(`does NOT stand on its own origin — it sits ${where}. A node at [0,0,0] puts it there too; offset the node, or expect an empty-looking frame`);
89
+ }
90
+ if (v.embeddedClips.length > 0) lines.push(`clips in the file: ${v.embeddedClips.join(", ")} (play by name, no asset needed)`);
91
+ return lines.join("\n");
92
+ }
93
+ //#endregion
7
94
  //#region src/3d/terrain-nav.ts
8
95
  function buildTerrainNav(terrain, opts) {
9
96
  const cellSize = opts?.cellSize ?? 2;
@@ -115,4 +202,4 @@ function createNavDebugNode(nav, opts) {
115
202
  return node;
116
203
  }
117
204
  //#endregion
118
- 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, SIGNATURE_GRID, StaticBody3D, TERRAIN_THEMES, Terrain3D, TextureCache3D, Trail3D, Tree3D, VOXEL_PALETTE, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, acquireOwnTexture, acquireTexture, buildHeightmap, buildRiverRings, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, diffSignatures, diffText, enablePhysics3D, findRiverCoverageGaps, frameSignature, frameStats, frameText, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, projectToRiver, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, riverStepFor, setEnvironment3D, smoothCourse, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath };
205
+ 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, SIGNATURE_GRID, StaticBody3D, TERRAIN_THEMES, Terrain3D, TextureCache3D, Trail3D, Tree3D, VOXEL_PALETTE, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, acquireOwnTexture, acquireTexture, buildHeightmap, buildRiverRings, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, diffSignatures, diffText, enablePhysics3D, findRiverCoverageGaps, frameSignature, frameStats, frameText, horizonColorFromSky, keyboardIntensity, modelVerdict, movementState, parseEnvironment3D, projectToRiver, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, riverStepFor, setEnvironment3D, smoothCourse, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath, verdictText };
@@ -3,7 +3,7 @@ import { n as loadScene, o as computeViewport, s as resolveViewport, v as diagno
3
3
  import { h as Engine, m as AudioPlayer } from "./register-BSXV8T9F.js";
4
4
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
5
5
  import { i as resolveRendering, n as attachTouchControls } from "./touch-BoNg_MnF.js";
6
- import { a as openBundledEditor, i as devServerLibrary, n as pauseWhenHidden, r as crossFade, t as teardown } from "./teardown-yePMOE1K.js";
6
+ import { a as openBundledEditor, i as devServerLibrary, n as pauseWhenHidden, r as crossFade, t as teardown } from "./teardown-BKTCzLek.js";
7
7
  import { n as registerGameplayBehaviors } from "./gameplay-BQOeAid6.js";
8
8
  import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-R2JTnIMw.js";
9
9
  import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
@@ -3,12 +3,12 @@ import { n as loadScene, v as diagnose, w as registerBehavior } from "./loader-r
3
3
  import { _ as qualityCaps, h as Engine, m as AudioPlayer, y as qualityRendering } from "./register-BSXV8T9F.js";
4
4
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
5
5
  import { i as resolveRendering, n as attachTouchControls } from "./touch-BoNg_MnF.js";
6
- import { a as openBundledEditor, i as devServerLibrary, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, t as teardown } from "./teardown-yePMOE1K.js";
6
+ import { a as openBundledEditor, i as devServerLibrary, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, t as teardown } from "./teardown-BKTCzLek.js";
7
7
  import { B as createCausticsQuad, F as PhysicsBody3D, R as Node3D, n as registerGameplayBehaviors } from "./gameplay-BQOeAid6.js";
8
8
  import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
9
- import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-DUsBqvtk.js";
10
- import { a as frameStats, i as frameSignature } from "./frame-report-Lr3VO24R.js";
11
- import { n as enablePhysics3D } from "./physics-3d-DFqMtBUD.js";
9
+ import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-D1b0ydTS.js";
10
+ import { a as frameSignature, i as frameImage, o as frameStats } from "./frame-report-njybhZon.js";
11
+ import { n as enablePhysics3D } from "./physics-3d-CSoGjM8P.js";
12
12
  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";
13
13
  import { VRMLoaderPlugin, VRMUtils } from "@pixiv/three-vrm";
14
14
  import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
@@ -1545,6 +1545,12 @@ function prune(obj, visited) {
1545
1545
  //#endregion
1546
1546
  //#region src/3d/renderer.ts
1547
1547
  /**
1548
+ * How long a capture waits for the game's own loop before drawing its own
1549
+ * frame. Long enough that a running game answers from its normal loop (16ms),
1550
+ * short enough that a paused or occluded tab still answers promptly.
1551
+ */
1552
+ const CAPTURE_NUDGE_MS = 120;
1553
+ /**
1548
1554
  * WebGL presentation layer: subscribes to `engine.updated`, mirrors the active
1549
1555
  * scene's node tree onto a three.js scene, applies the scene `environment`
1550
1556
  * header (ambient/background/sky/fog/shadows/exposure — see Environment3D),
@@ -1890,6 +1896,14 @@ var Renderer3D = class {
1890
1896
  resolve,
1891
1897
  reject
1892
1898
  });
1899
+ setTimeout(() => {
1900
+ if (this.pendingCaptures.length > 0) try {
1901
+ this.render();
1902
+ } catch (error) {
1903
+ const e = error instanceof Error ? error : new Error(String(error));
1904
+ for (const w of this.pendingCaptures.splice(0)) w.reject(e);
1905
+ }
1906
+ }, CAPTURE_NUDGE_MS);
1893
1907
  });
1894
1908
  }
1895
1909
  pendingCaptures = [];
@@ -2446,11 +2460,16 @@ async function createGame3D(opts) {
2446
2460
  const onFrameRequest = (data) => {
2447
2461
  const request = data;
2448
2462
  const id = request?.id;
2463
+ hot.send("incanto:frame-ack", { id });
2449
2464
  captureFramePixels().then((shot) => hot.send("incanto:frame-report", {
2450
2465
  id,
2451
2466
  report: {
2452
2467
  ...frameStats(shot.pixels, shot.width, shot.height, { grid: request?.grid }),
2453
- signature: frameSignature(shot.pixels, shot.width, shot.height)
2468
+ signature: frameSignature(shot.pixels, shot.width, shot.height),
2469
+ ...request?.image ? { image: frameImage(shot.pixels, shot.width, shot.height, (w, h) => Object.assign(document.createElement("canvas"), {
2470
+ width: w,
2471
+ height: h
2472
+ }), request.image) } : {}
2454
2473
  }
2455
2474
  })).catch((error) => hot.send("incanto:frame-report", {
2456
2475
  id,
@@ -60,7 +60,7 @@ type LibrarySearch = (query: {
60
60
  keyword?: string;
61
61
  page?: number;
62
62
  limit?: number;
63
- }) => Promise<{
63
+ }, token?: string) => Promise<{
64
64
  items: unknown[];
65
65
  page: number;
66
66
  hasNext: boolean;