wave3d-agent-sdk 0.2.14 → 0.2.16

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/cli.js CHANGED
@@ -531,6 +531,7 @@ var PROJECT_ASSET_ACCESSOR_BUCKETS = [
531
531
  "materials",
532
532
  "textures",
533
533
  "animations",
534
+ "vertexAnimations",
534
535
  "poses",
535
536
  "audios",
536
537
  "instruments",
@@ -545,17 +546,14 @@ var PROJECT_ASSET_ACCESSOR_BUCKETS = [
545
546
  ];
546
547
 
547
548
  // ../../wave-engine/dist/src/core/coreAbstractions/objectModel/waveModelMetadataKeys.js
548
- var WAVE_MODEL_PART_ID_METADATA_KEY = "waveModelPartId";
549
- var WAVE_MODEL_PART_NAME_METADATA_KEY = "waveModelPartName";
550
- var WAVE_MODEL_PART_METADATA_KEY = "waveModelPartMetadata";
551
549
  var WAVE_MODEL_RIG_GRAPH_METADATA_KEY = "waveModelRigGraphMetadata";
550
+ var WAVE_MODEL_OBJECT_MODEL_METADATA_KEY = "waveModelObjectModel";
552
551
 
553
552
  // ../../wave-engine/dist/src/core/coreAbstractions/objectModel/waveModelPartTypes.js
554
553
  var WaveModelPartScope;
555
554
  (function(WaveModelPartScope2) {
556
555
  WaveModelPartScope2["Available"] = "available";
557
556
  WaveModelPartScope2["Created"] = "created";
558
- WaveModelPartScope2["Promoted"] = "promoted";
559
557
  WaveModelPartScope2["All"] = "all";
560
558
  })(WaveModelPartScope || (WaveModelPartScope = {}));
561
559
  var WaveModelPartLifecycleState;
@@ -41609,7 +41607,7 @@ var DEFAULT_PHYSICS = {
41609
41607
  };
41610
41608
 
41611
41609
  // ../../src/lib/waveStudio/assets/contracts/waveStudioEngineAssetContracts.ts
41612
- var WAVE_STUDIO_ENGINE_ACCESSOR_BUCKET_EXTENSIONS = ["cubeMaps", "poses"];
41610
+ var WAVE_STUDIO_ENGINE_ACCESSOR_BUCKET_EXTENSIONS = ["cubeMaps", "poses", "vertexAnimations"];
41613
41611
  function withAccessorBucketExtensions(buckets) {
41614
41612
  const existingBuckets = new Set(buckets);
41615
41613
  return Object.freeze([
@@ -41620,10 +41618,11 @@ function withAccessorBucketExtensions(buckets) {
41620
41618
  var WAVE_STUDIO_ENGINE_ASSET_TYPES = PROJECT_ASSET_TYPES;
41621
41619
  var WAVE_STUDIO_ENGINE_ACCESSOR_BUCKETS = withAccessorBucketExtensions(PROJECT_ASSET_ACCESSOR_BUCKETS);
41622
41620
  var WAVE_STUDIO_MODEL_METADATA_KEYS = Object.freeze({
41623
- partId: WAVE_MODEL_PART_ID_METADATA_KEY,
41624
- partName: WAVE_MODEL_PART_NAME_METADATA_KEY,
41625
- partMetadata: WAVE_MODEL_PART_METADATA_KEY,
41626
- rigGraph: WAVE_MODEL_RIG_GRAPH_METADATA_KEY
41621
+ objectModel: WAVE_MODEL_OBJECT_MODEL_METADATA_KEY,
41622
+ rigGraph: WAVE_MODEL_RIG_GRAPH_METADATA_KEY,
41623
+ partMetadata: "partMetadata",
41624
+ partId: "partId",
41625
+ partName: "partName"
41627
41626
  });
41628
41627
 
41629
41628
  // ../../src/lib/waveStudio/assets/contracts/waveStudioSerializedDataAssetContracts.ts
@@ -41996,23 +41995,36 @@ var WAVE_STUDIO_PRIMARY_ASSET_BUCKET_SPECS = Object.freeze([
41996
41995
  },
41997
41996
  {
41998
41997
  bucket: "animations",
41999
- assetTypes: ["animation", "vertexAnimation"],
41998
+ assetTypes: ["animation"],
42000
41999
  label: "Animation",
42001
42000
  pluralLabel: "Animations",
42002
42001
  defaultExtension: ".anim.json",
42003
42002
  baseCategoryAliases: [
42004
42003
  "animations",
42005
42004
  "animation",
42006
- "fbx_animation",
42005
+ "fbx_animation"
42006
+ ],
42007
+ pathFolderAliases: ["animations"],
42008
+ pathExtensions: ["anim.json", "glb", "gltf", "fbx"],
42009
+ assetManagerAlias: "animationNames",
42010
+ monaco: { interfaceName: "AnimationNames", propertyName: "animationNames" }
42011
+ },
42012
+ {
42013
+ bucket: "vertexAnimations",
42014
+ assetTypes: ["vertexAnimation"],
42015
+ label: "Vertex Animation",
42016
+ pluralLabel: "Vertex Animations",
42017
+ defaultExtension: ".vat.json",
42018
+ baseCategoryAliases: [
42007
42019
  "vertexanimation",
42008
42020
  "vertexanimations",
42009
42021
  "vertex_animation",
42010
42022
  "vat"
42011
42023
  ],
42012
- pathFolderAliases: ["animations"],
42013
- pathExtensions: ["anim.json", "vat.json", "glb", "gltf", "fbx"],
42014
- assetManagerAlias: "animationNames",
42015
- monaco: { interfaceName: "AnimationNames", propertyName: "animationNames" }
42024
+ pathFolderAliases: ["vertexAnimations", "vertexanimations"],
42025
+ pathExtensions: ["vat.json"],
42026
+ assetManagerAlias: "vertexAnimationNames",
42027
+ monaco: { interfaceName: "VertexAnimationNames", propertyName: "vertexAnimationNames" }
42016
42028
  },
42017
42029
  {
42018
42030
  bucket: "poses",
@@ -42520,8 +42532,8 @@ function normalizeWaveGenieAssetUploadRequest(request) {
42520
42532
 
42521
42533
  // ../../src/lib/waveStudio/aiAssist/bridge/localAgentSdkContract.ts
42522
42534
  var WAVE3D_AGENT_SDK_PACKAGE_NAME = "wave3d-agent-sdk";
42523
- var WAVE3D_AGENT_SDK_REQUIRED_VERSION = "0.2.14";
42524
- var WAVE3D_AGENT_SDK_REQUIRED_BUILD = "agent-sdk-20260625.2";
42535
+ var WAVE3D_AGENT_SDK_REQUIRED_VERSION = "0.2.16";
42536
+ var WAVE3D_AGENT_SDK_REQUIRED_BUILD = "agent-sdk-20260627.2";
42525
42537
  var WAVE3D_AGENT_SDK_PACKAGE_SPEC = `${WAVE3D_AGENT_SDK_PACKAGE_NAME}@${WAVE3D_AGENT_SDK_REQUIRED_VERSION}`;
42526
42538
  var WAVE3D_AGENT_SDK_START_COMMAND = `npx -y ${WAVE3D_AGENT_SDK_PACKAGE_SPEC} start`;
42527
42539
  var WAVE3D_AGENT_SDK_TOKEN_ENV_VAR = "WAVE3D_MCP_TOKEN";
@@ -43559,7 +43571,7 @@ function buildWaveMcpTaskRouteRecommendedNextToolCall(route) {
43559
43571
  if (route.editIntent === "modifyAssets") {
43560
43572
  return {
43561
43573
  tool: "find_wave_assets_by_category | upload_wave_asset | create_wave_asset_upload | rename_wave_asset | delete_wave_asset",
43562
- arguments: { category: "<models|textures|materials|audios|hdr|animations|...>" },
43574
+ arguments: { category: "<models|textures|materials|audios|hdr|animations|vertexAnimations|...>" },
43563
43575
  note: "Use category first to reduce search space."
43564
43576
  };
43565
43577
  }
@@ -44249,14 +44261,14 @@ var WAVE_AUTHORING_CORE_INTENT_STAMPS = [
44249
44261
  "State/mode/phase: entity state APIs such as enter/whenIn/onEnter/onExit/toggle/cycle/blockEnterFor before boolean flag machines.",
44250
44262
  "Reaction/observation: when(...).do(...), whenAccelerating()/whenDecelerating(), distance/speed/threshold/rate builders before manual polling or speed-delta state.",
44251
44263
  "Chance/variety: atChanceOf, cycleThrough, and choice APIs before raw Math.random gates.",
44252
- "Player/controller movement: wave.physics.kinematic-controller-authoring, waveKinematicActor<TState>, and actor-level asHumanoid/asVehicle/asFlight builders before Actor/waveActor, raw input polling, rigid-body forces, or per-tick movement loops.",
44264
+ "Player/controller movement: wave.physics.kinematic-controller-authoring, waveHumanoid for normal humanoid players, waveKinematicActor<TState> for vehicle/flight/generic controllers, and actor-level asHumanoid/asVehicle/asFlight builders before Actor/waveActor, raw input polling, rigid-body forces, or per-tick movement loops.",
44253
44265
  "Repetition/placement: repeat, placeAround, spawnAround, grid/group placement before manual spatial loops.",
44254
44266
  "Terrain/world population: wave.world.world-elements and scene.world/world bootstrap builders for forests, grass, rocks, water, entities, or custom content tied to terrain/streaming world surfaces. Prefer scene.world.scatter(...).renderAs(...).density(...).randomScale(...).apply() or world.scatter(...) before local spawn loops, scene placement, or instancing/batching.",
44255
44267
  "Terrain vs ground: myScene.terrain owns terrain recipe/controller state; myScene.ground is the camera-local live tile entity for visual overlays, callbacks, transform/tooling, and inspection only.",
44256
44268
  "Multiplicity/performance: wave.group.instancing-and-batching for local repeated model-backed objects; classify per-instance needs before choosing real entities, InstanceMeshGroup/waveInstanceGroup/waveInstanceMesh, or waveThinBatch. Count alone never chooses thin batch. Terrain/world/streamed population is a separate world-elements route.",
44257
44269
  'Soft custom geometry: wave.geometry.sdf-surface and assetManager.createSdfSurface("assetName") recipes for buns, cushions, puffy/squishy toys, and organic rounded forms before plain primitives, raw mesh buffers, or vertex editing.',
44258
44270
  "Path-bound surface geometry: wave.geometry.surface-ribbons and wavePathSurface for roads, trails, walkways, bridge decks, waterfalls, and continuous strips before asset-manager factories, scattered planes/cubes, or raw mesh buffers.",
44259
- "Asset argument vs authoring: typed refs such as models.<asset>, textures.<asset>, materials.<asset>, audios.<asset>, hdr.<asset>, cubeMaps.<asset>, and animations.<asset> for existing assets; waveMaterial for material handles; assetManager only when an exact skill/API requires a low-level generated asset factory."
44271
+ "Asset argument vs authoring: typed refs such as models.<asset>, textures.<asset>, materials.<asset>, audios.<asset>, hdr.<asset>, cubeMaps.<asset>, animations.<asset>, and vertexAnimations.<asset> for existing assets; waveMaterial for material handles; assetManager only when an exact skill/API requires a low-level generated asset factory."
44260
44272
  ];
44261
44273
  var WAVE_AUTHORING_CORE_INTENT_PASS_QUICK_GUIDE = [
44262
44274
  WAVE_AUTHORING_CORE_RULES.coreIntentPass,
@@ -44359,7 +44371,7 @@ function buildWaveMcpAuthoringReminder(kind) {
44359
44371
  ...base,
44360
44372
  nextStep: "Use exact asset refs as method inputs, then return to the authoring strategy.",
44361
44373
  checklist: [
44362
- "Use returned code refs exactly, such as models.X, textures.X, materials.X, audios.X, or animations.X.",
44374
+ "Use returned code refs exactly, such as models.X, textures.X, materials.X, audios.X, animations.X, or vertexAnimations.X.",
44363
44375
  "For authoring new materials, prefer waveMaterial; quote materials.X only for existing material assets.",
44364
44376
  "If a newly referenced asset changes bootstrap needs, let Studio hot reload escalate internally."
44365
44377
  ],
@@ -44465,7 +44477,7 @@ var WAVE_MCP_AGENT_BRIEF = [
44465
44477
  "VFS modules: scene-root modules and their owned helpers run inside the Studio authoring context, but helpers should stay pure or parameterized. Put live object ownership in scene-root/feature files, not shared helpers.",
44466
44478
  'VFS HTML sketches: for diagram/chart/doc-sketch requests, create or edit an exact `.html` file with Studio VFS tools. Mermaid renders from `<div class="mermaid">flowchart TD ...</div>` when that HTML file is active in the editor/coding pane; HTML sketches must never replace the live engine preview iframe. Do not put Mermaid in markdown fences unless user specifically wants markdown text.',
44467
44479
  'VFS hot reload ownership: Studio hot reload targets the active/open edited file when safe. Editing `/main.ts` reloads the main graph; editing a scene-root module reloads that root; bootstrap/scene registry/assets/network/ambiguous helper surfaces escalate. In multi-file projects, standalone `hot_reload_wave_preview` follows the active Studio editor file, so do not expect it to reload an arbitrary unopened module by path. Put heavy world loading in bootstrap or a coarse world module. Static VFS/package/asset-surface changes can be detected from file/package diffs and Studio may upgrade the tier automatically. Runtime-authored UI state changes cannot be inferred from files; if UI in `main.ts` changes bootstrap/world-provider/runtime-envelope state, store the state and call `waveStudio.reloadPreview({ reason, invalidates: ["world-provider"] })`. Valid invalidations are `bootstrap`, `world-provider`, and `runtime-envelope`. Do not call `myScene.hotReload(...)` from Studio-authored code because it bypasses Studio VFS/package/source-patch orchestration. For intentional cross-module live entities, the owner module calls `waveStudio.exportEntity("Name", entity)` and importer modules call `waveStudio.importEntity<T>("Name")`; Studio restores the exported baseline and replays active importer overlays during source hot reload. Source execution order is dependency-driven: exporter roots run before importer roots; an exporter root runs before `main.ts` when main imports it; importer overlays run after exporter/main baseline. Entity names must be static string literals, unique, and acyclic or run/hot reload stops before execution. Keep shared helpers pure or parameterized.',
44468
- "Assets: when quoting or passing an existing asset, use typed bare refs in main files: `models.X`, `textures.X`, `materials.X`, `audios.X`, `hdr.X`, `cubeMaps.X`, `animations.X`, etc. Do not paste raw paths or edit Studio-managed generated files just to register assets. If the exact ref is not already visible, call category-first asset discovery (`find_wave_assets_by_category`, alias `list_wave_assets_by_category`, alias `search_wave_assets_by_category`, or tolerant `list_wave_assets`) with required `category` from user intent, semantic `query`, and small `limit` before editing code; category-filtered results can still be capped/truncated, so refine query before concluding absence. Use `list_wave_explorer_assets` only for uploaded library metadata, rename/delete, URL, path, size, or display/ref-name management.",
44480
+ "Assets: when quoting or passing an existing asset, use typed bare refs in main files: `models.X`, `textures.X`, `materials.X`, `audios.X`, `hdr.X`, `cubeMaps.X`, `animations.X`, `vertexAnimations.X`, etc. Do not paste raw paths or edit Studio-managed generated files just to register assets. If the exact ref is not already visible, call category-first asset discovery (`find_wave_assets_by_category`, alias `list_wave_assets_by_category`, alias `search_wave_assets_by_category`, or tolerant `list_wave_assets`) with required `category` from user intent, semantic `query`, and small `limit` before editing code; category-filtered results can still be capped/truncated, so refine query before concluding absence. Use `list_wave_explorer_assets` only for uploaded library metadata, rename/delete, URL, path, size, or display/ref-name management.",
44469
44481
  "Asset authoring facade split: typed refs quote existing assets; `waveMaterial` authors material handles; `assetManager` is only for exact asset-pipeline/generated-asset APIs that a local SDK skill or API lookup names, such as SDF surfaces or surface ribbons. Do not treat `assetManager` as the default creative facade for materials or normal asset arguments.",
44470
44482
  "Material authoring: when creating, configuring, forking, or intentionally editing material handles, route to `wave.material.authoring` and start from `waveMaterial` (`createWater`, `createGrid`, `createSplatMaterial`, `createFromAsset`, `editAsset`). If a material handle later needs runtime sync, `assetManager` may be passed as the sync target; it is still not the authoring root.",
44471
44483
  "Preview: default to hot reload after code changes. On the final edit use `awaitHotReload: true` when you want edit + hot reload + diagnostics in one response; `requestHotReload:true` now also waits for diagnostics by default unless paired with `awaitHotReload:false`. Standalone `run_wave_preview` / `hot_reload_wave_preview` wait by default and return same-call bounded diagnostics in `runtimeVerification`; set `awaitRuntimeResult:false` only for intentional fire-and-poll. Wave Studio may upgrade the hot-reload tier internally for asset/bootstrap/runtime-surface changes, including a full scene rebuild only when required. Caveat: standalone `hot_reload_wave_preview` mirrors the toolbar button and reloads the currently open/active TypeScript file in multi-file projects; it does not take a target path or reload every user-created .ts module. Use `pause_wave_preview` / `resume_wave_preview` for toolbar-equivalent engine pause/resume.",
@@ -44487,8 +44499,8 @@ var WAVE_MCP_AUTHORING_GLOBALS_GUIDE = [
44487
44499
  "- Intent/loop/time values: `Animate`, `Snapshot`, `Repeat`, `ToTrue`, `ToFalse`, `Flips`, `FirstTime`, `EveryTime`, `PerSecond`, `PerTick`, `Ticks`, `Seconds`, `UnitsPerSecond`, `DegreesPerSecond`. For immediate transform/property changes, omit the mode argument; `Apply` is internal transform plumbing, not a public authoring token.",
44488
44500
  "- Direction and input enum-style globals: `Direction.X/Y/Z`, `Direction.Left/Right/Up/Down/Forward/Backward`, `Keyboard`, `MouseButton`, `GamepadButton`, `InputPhase`, `MovementMode`, `RotationMode`.",
44489
44501
  "- Colors/materials/fx helpers: `COLOR`, `PALETTE`, `waveCOLOR`, `waveMaterial`, `shaderUniform`, `waveFx`, `waveFxPresets`, `FxAnchor`, `FxCondition`.",
44490
- "- Controller movement helpers: `waveKinematicActor`, `netKinematicActor`, `KinematicHumanoidMovementState`, `KinematicVehicleMovementState`, and `KinematicFlightMovementState`. Use actor-level `.asHumanoid(...)`, `.asVehicle(...)`, or `.asFlight(...)` for player/controller movement.",
44491
- "- Asset maps: use category-first refs returned by `find_wave_assets_by_category`, commonly `models`, `gaussianSplats`, `animations`, `materials`, `guis`, `textures`, `audios`, `instruments`, `videos`, `hdr`, `fonts`, `serializedData`, `terrains`, `fx`, and `particles`.",
44502
+ "- Controller movement helpers: `waveHumanoid`, `netHumanoid`, `waveKinematicActor`, `netKinematicActor`, `KinematicHumanoidMovementState`, `KinematicVehicleMovementState`, and `KinematicFlightMovementState`. Use `waveHumanoid` plus `.useDefaultLocomotionAnimations()` for normal humanoid players; use `.asVehicle(...)` or `.asFlight(...)` on `waveKinematicActor<TState>` for vehicle/flight controllers.",
44503
+ "- Asset maps: use category-first refs returned by `find_wave_assets_by_category`, commonly `models`, `gaussianSplats`, `animations`, `vertexAnimations`, `materials`, `guis`, `textures`, `audios`, `instruments`, `videos`, `hdr`, `fonts`, `serializedData`, `terrains`, `fx`, and `particles`.",
44492
44504
  '- Scene/runtime handles: prefer `myScene` for scene composition and `waveStudio` for Studio operations. If authored UI changes bootstrap/world-provider/runtime-envelope state and needs the Studio preview package to rebuild, call `waveStudio.reloadPreview({ reason, invalidates: ["world-provider"] })`, not `myScene.hotReload(...)`. Valid invalidations are `bootstrap`, `world-provider`, and `runtime-envelope`; use the narrowest true reason. `assetManager` is available, but use it only when an exact skill/API names an asset-pipeline or generated-asset factory; do not use it as the default facade for existing asset refs or material authoring. Use lower-level `ctx`, `engine`, or `scene` only when existing code or an exact API requires them.',
44493
44505
  "- Authoring systems/presets: `waveEventBus`, `waveRig`, `waveValueCurve`, `waveValueCurvePresets`, `waveMotionSignal`, `waveParam`, `WaveParam`, `WaveChoice`, `prefabModels`, `effectPrefabs`, and prefab helpers such as `rocketPrefab`.",
44494
44506
  "- Lowercase constructors: `prop`, `marker`, `sphere`, `point`, `cube`, `box`, `cylinder`, `capsule`, `cone`, `torus`, `plane`, `ground`, `line`, `arc`, `path`, and related shape helpers.",
@@ -44514,14 +44526,14 @@ var WAVE_MCP_CODING_GUARDRAIL = [
44514
44526
  "4d. For terrain/world population such as forests, grass, rocks, water, streamed entities, or environmental scatter tied to terrain/streaming surfaces, route to `wave.world.world-elements`: use `scene.world.scatter(...)`/`myScene.world.scatter(...)` for live scene code or `world.scatter(...)` inside `scene.withWorldStreaming(...)` for bootstrap streaming declarations. Prefer fluent verbs like `.renderAs(...)`, `.density(...)`, `.randomScale(...)`, `.colors(...)`, `.linkedTo(...)`, `.usePartitionedLOD(...)`, `.distanceBands(...)`, `.lodModels(...)`, then `.apply()`. Do not hand-roll spawn loops or use local instancing/batching when declarative world scatter fits.",
44515
44527
  '4e. For many local repeated model-backed objects such as a fleet, crowd, stars, decorations, or "1000 spaceships", route to `wave.group.instancing-and-batching` and classify per-instance needs before constructors. Use `waveThinBatch` only for visual-only mass sharing one mesh with per-instance transform/color/GPU animation. Use `waveInstanceMesh`, `InstanceMeshGroup`, or scene `waveInstanceGroup` when each copy needs picking, click/hover interaction, labels/tool overlays, visibility toggles, selection, or individual identity. Use real `Prop`/`Actor` entities when each copy needs rigid bodies, gravity, audio, AI, weapons, damage state, independent lifecycle, or rich behavior. Count alone never chooses thin batch; mixed hero/background intent should use a hybrid.',
44516
44528
  '4e1. For visual-model voxelization, route to `wave.model.voxelization`. Prefer `source.model.voxelizing().relativeSize(0.05).surfaceOnly().onWorkerThread().usingCubes().asThinBatch().applyAsync()` only when async/worker authored code is explicitly acceptable; otherwise use synchronous `onMainThread().apply()` only for tiny local voxel work where blocking is acceptable. Never use Promise chains such as `.apply().then(...)` in authored Studio code because hot-reload safety rejects `.then/.catch/.finally`. Use `relativeSize(ratio)` for model-scale-independent voxel size, `size(value)` only for absolute world units, `usingCubes()`/`usingSpheres()`/`usingCylinders()`/`usingCapsules()` for shape, and the one-shot `voxelize({ size: { mode: "relative", ratio: 0.05, basis: "longestAabbEdge" }, execution: "workerThread", shape: "cube", surfaceOnly: true })` only for serializable recipe code. For thin-batch voxel interactions, use `detectNear(target).within(radius)`, `batchTransform.getColorAt(index)` before color restore, `whenIndexClicked(index => voxelBatch.at(index).enlargeBy(1.2).done().commitBuffers())`, and `castToProp(index); prop.enablePhysics()` only when a full prop is needed. Do not use removed `voxelizeHeavy`, `voxelize({ voxelSize })`, `withVoxelSize`, `sharedBox`, `atIndex`, or low-level worker/adapter internals in authored scene code.',
44517
- "4f. For player/controller movement, route to `wave.physics.kinematic-controller-authoring`: use `waveKinematicActor<TState>` or `netKinematicActor` and actor-level `.asHumanoid(...)`, `.asVehicle(...)`, or `.asFlight(...)` builders. Do not start from `Actor`/`waveActor`, raw input polling, rigid-body forces, per-tick movement loops, or direct `movementController.useFlightScheme(...)` unless the user explicitly asks for low-level component tuning or nearby working code already uses that component-level pattern.",
44518
- "4f1. For basic public humanoid locomotion animation, follow the kinematic-obby pattern: `new waveKinematicActor<KinematicHumanoidMovementState>().useModel(models.wave3dFemale)`, then `.asHumanoid({ baseSpeed, jumpForce }).useIdleAnimation(animations.Idle).useWalkingAnimation(animations.Walking).useJumpAnimation(animations.Jump).apply()`. Do not use `animator.addLocalAnimations()`, `getClipNames()`, or `resolveClipName(...)` as the first-choice setup when public `animations.*` refs fit.",
44529
+ "4f. For player/controller movement, route to `wave.physics.kinematic-controller-authoring`: use `waveHumanoid`/`netHumanoid` for humanoid player characters, and use `waveKinematicActor<TState>`/`netKinematicActor` with `.asVehicle(...)` or `.asFlight(...)` for vehicle/flight/generic controller movement. Do not start from `Actor`/`waveActor`, raw input polling, rigid-body forces, per-tick movement loops, or direct `movementController.useFlightScheme(...)` unless the user explicitly asks for low-level component tuning or nearby working code already uses that component-level pattern.",
44530
+ "4f1. For basic public humanoid locomotion animation, follow the kinematic-obby pattern: `new waveHumanoid().useModel(models.wave3dFemale).useDefaultLocomotionAnimations()`. For custom locomotion tuning or clip options, use `.asHumanoid({ baseSpeed, jumpForce }).useIdleAnimation(animations.Idle).useWalkingAnimation(animations.Walking).useJumpAnimation(animations.Jump).apply()`. Do not use `animator.addLocalAnimations()`, `getClipNames()`, or `resolveClipName(...)` as the first-choice setup when public `animations.*` refs fit.",
44519
44531
  "4g. For obbies/course obstacles, split the intent: the controlled player uses `wave.physics.kinematic-controller-authoring`; static platforms, moving platforms, sliding gates, sweepers, ferries, and hazards use `wave.physics.rigid-body-authoring` on geometry/props with static or kinematic rigid bodies, then transform/animate/current-code motion. Do not use `waveKinematicActor` for a platform unless it is itself player/controller-driven.",
44520
44532
  '4h. For semantic touch lifecycle such as "when contact starts/stops", "exactly once when touching begins/ends", "on hit", or projectile/target impact reactions, use `onContactBegin(...)`, `onContactContinue(...)`, `onContactEnd(...)`, or tag/target variants. Do not use removed `onCollision*` callback aliases; collision-named surfaces are for filtering, masks, groups, and actuation internals.',
44521
44533
  `4i. ${WAVE_AUTHORING_CORE_RULES.syncUserCode}`,
44522
44534
  `4j. ${WAVE_AUTHORING_CORE_RULES.terrainGroundRouting}`,
44523
44535
  "5. Use `get_wave_session` and `list_wave_files` to know active file context. `/main.ts` and scene `*/main.ts` get convenience globals: write against `myScene`, not a hand-created scene.",
44524
- `6. ${WAVE_AUTHORING_CORE_RULES.assetResolution} In main files, use bare asset maps like \`models.Foo\`, \`gaussianSplats.Room\`, \`textures.Grass\`, \`materials.Wood\`, \`animations.Idle\`, \`audios.Click\`, \`hdr.daylight\`, \`cubeMaps.studio\`, \`fonts.Poppins_Regular\`, \`serializedData.SomeJson\`. Do not add \`ASSET_WAREHOUSE.\` unless raw warehouse access is explicitly needed.`,
44536
+ `6. ${WAVE_AUTHORING_CORE_RULES.assetResolution} In main files, use bare asset maps like \`models.Foo\`, \`gaussianSplats.Room\`, \`textures.Grass\`, \`materials.Wood\`, \`animations.Idle\`, \`vertexAnimations.HorseGallopVat\`, \`audios.Click\`, \`hdr.daylight\`, \`cubeMaps.studio\`, \`fonts.Poppins_Regular\`, \`serializedData.SomeJson\`. Do not add \`ASSET_WAREHOUSE.\` unless raw warehouse access is explicitly needed.`,
44525
44537
  `6a. For authoring constants, prefer bare runtime globals declared by the Studio authoring environment. Common examples: ${WAVE_AUTHORING_COMMON_GLOBAL_EXAMPLES_TEXT}. The generated globals surface has many more values; use local-SDK \`query_wave_api\` before inventing namespace-qualified paths such as \`TransformVerbMode.Animate\` in authored code. HTTP Gateway hides/retires skill/API lookup.`,
44526
44538
  "6b. Asset facade split: passing an existing asset uses typed refs such as `models.X`, `textures.X`, `materials.X`, or `audios.X`; material authoring starts from `waveMaterial`; `assetManager` is reserved for exact low-level generated-asset/asset-pipeline APIs named by a local SDK skill or API lookup. Do not use `assetManager` as the default material, asset-ref, or path-surface authoring root.",
44527
44539
  '7. Use category-first asset discovery before referencing uploaded user assets, project aliases, or ambiguous built-in assets. Preferred tool: `find_wave_assets_by_category`; aliases: `list_wave_assets_by_category`, `search_wave_assets_by_category`, tolerant `list_wave_assets`. Choose category from user intent first, then query: `list_wave_assets_by_category({ category:"materials", query:"grass", limit:50 })`. For sound use `audios`, for 3D objects use `models`, for sky/HDR use `hdr`, for cube-map sky/environment use `cubeMaps`, for images use `textures`. Category-filtered responses can still be capped/truncated; absence there is not absence in the library. Only use asset refs returned by this tool. If the current code already contains the exact ref and the user asks for a small pattern-preserving edit, you may reuse that visible ref.',
@@ -44533,7 +44545,7 @@ var WAVE_MCP_CODING_GUARDRAIL = [
44533
44545
  '11. After the final code edit, default to hot reload. Prefer `awaitHotReload: true` on the edit tool when you want one MCP response with edit result + hot reload + bounded diagnostics. `requestHotReload:true` also waits for diagnostics by default unless paired with `awaitHotReload:false`. Standalone `run_wave_preview` / `hot_reload_wave_preview` also wait by default and return `runtimeVerification`; set `awaitRuntimeResult:false` only for intentional fire-and-poll. Caveat: standalone `hot_reload_wave_preview` mirrors the toolbar button and reloads the currently open/active TypeScript file in multi-file projects; it does not take a target path or reload every user-created .ts module. That hot-reload request may internally upgrade from `patchMain` to `preserveScene` or hard `rebuildScene` when assets/bootstrap/scene surface changed; do not manually force bootstrap sync. Runtime-authored UI that changes bootstrap/world-provider/runtime-envelope state must call `waveStudio.reloadPreview({ reason, invalidates: ["world-provider"] })` because Studio cannot infer that from static file diffs. Use `run_wave_preview` only when diagnostics show no successful preview yet (`hasRunSucceeded: false`), the user explicitly asks for a full run/restart, or hot reload/polling fails and a full restart is the last resort. `pause_wave_preview` and `resume_wave_preview` are direct preview controls mirroring the toolbar pause/resume buttons.',
44534
44546
  '12. After run/hot reload, use returned `runtimeVerification` when present; otherwise call `get_wave_runtime_diagnostics` repeatedly until `runtimeBusy` is false and `lastRuntimeOutcome` is `success` or `error`. Use `previewExecutionPhase` to distinguish Studio preparing work from the preview iframe executing it. `isRunning` is only the Studio scheduling flag, not the final runtime completion gate. If the edit/runtime tool returned `requestedAt` or `runtimeActionRequestedAt`, ignore diagnostics whose `lastRuntimeOutcomeAt` is older than that timestamp. Treat `latestError` as current only when `lastRuntimeOutcome` is `error`; older error lines can remain in returned logs as history. Treat `editorErrorCount > 0` as blocking Monaco/linter/compile failure and read `editorDiagnostics` before claiming success, even when `lastRuntimeOutcome` is `success`. If `lastRuntimeOutcome` is `success` and `editorErrorCount` is 0, verify visually with `capture_wave_screenshot({ resolution: "L" })` or structurally with `get_wave_runtime_entity_snapshot({ variableName, filePath? })` instead of declaring failure from old log text. Same-machine screenshots usually return `localPath`; hosted screenshots return exact field `dataBase64`, not `imageBase64`.',
44535
44547
  "12a. Marker waypoint workflow: when the human asks to use preview marking tools such as `clickToMark()`, route with `marker.use` plus the code/project intent, then call `list_wave_runtime_markers`. Treat marker records as runtime observation data, write marker `worldPosition`/`worldRotation` into the appropriate path/waypoint/placement code, hot reload, and verify with screenshot or marker re-read. One marker read may happen before routing only when needed to decide the code intent. Use path/placement skills only when current code does not reveal the marker-to-code pattern.",
44536
- `13. To use locally generated assets in code, prefer \`create_wave_asset_upload\` for local files when available: pass assetKind from the Wave Studio upload policy SSOT (${getWaveStudioBridgeAssetUploadKindHelpText()}), stat the file first, pass exact byte size, get \`uploadUrl\` + \`uploadHeaders\`, upload raw bytes with plain HTTP PUT using every returned header exactly, keep \`clientToken\`/\`uploadHeaders.Authorization\` out of logs, call \`get_wave_asset_upload_status\` until \`receivedBytes === sizeBytes\`, then call \`commit_wave_asset_upload\` with the same uploadId, assetKind, filename, contentType, and sizeBytes from the create response. No local Python, Vercel package, or Blob SDK is required. On hosted MCP this uses hosted temporary object storage; on same-machine local MCP it uses the local SDK as temporary staging. If direct upload is unavailable, use \`stage_wave_asset_upload_chunk\` plus \`commit_wave_asset_chunk_upload\`: omit uploadId only for chunkIndex 0, then reuse the returned uploadId for every later chunk and for commit. Use \`upload_wave_asset\` with exactly one of \`dataBase64\` or \`dataUrl\` only for small inline assets. If staging is abandoned before commit, call \`abort_wave_asset_upload\` with the uploadId. Do not abort after commit returns pending or completed; the Studio browser cleans committed staging after execution. Hosted MCP cannot read local filesystem paths through inline upload. All flows stage bytes outside the command queue, cap staged bytes at 300 MB, and return \`asset.bareRef\`, for example \`textures.Albedo\`, \`cubeMaps.Studio\`, \`materials.Wood\`, \`audios.Click\`, \`models.Robot\`, \`animations.Run\`, \`fonts.Title\`, or \`serializedData.Config\`. If the name already exists, the upload result returns \`skipped: true\` and the existing asset. Staged chunks/blobs are also swept lazily after about 24 hours. Model-family uploads enable meshoptimizer by default unless \`useMeshoptimizer\` is false.`,
44548
+ `13. To use locally generated assets in code, prefer \`create_wave_asset_upload\` for local files when available: pass assetKind from the Wave Studio upload policy SSOT (${getWaveStudioBridgeAssetUploadKindHelpText()}), stat the file first, pass exact byte size, get \`uploadUrl\` + \`uploadHeaders\`, upload raw bytes with plain HTTP PUT using every returned header exactly, keep \`clientToken\`/\`uploadHeaders.Authorization\` out of logs, call \`get_wave_asset_upload_status\` until \`receivedBytes === sizeBytes\`, then call \`commit_wave_asset_upload\` with the same uploadId, assetKind, filename, contentType, and sizeBytes from the create response. No local Python, Vercel package, or Blob SDK is required. On hosted MCP this uses hosted temporary object storage; on same-machine local MCP it uses the local SDK as temporary staging. If direct upload is unavailable, use \`stage_wave_asset_upload_chunk\` plus \`commit_wave_asset_chunk_upload\`: omit uploadId only for chunkIndex 0, then reuse the returned uploadId for every later chunk and for commit. Use \`upload_wave_asset\` with exactly one of \`dataBase64\` or \`dataUrl\` only for small inline assets. If staging is abandoned before commit, call \`abort_wave_asset_upload\` with the uploadId. Do not abort after commit returns pending or completed; the Studio browser cleans committed staging after execution. Hosted MCP cannot read local filesystem paths through inline upload. All flows stage bytes outside the command queue, cap staged bytes at 300 MB, and return \`asset.bareRef\`, for example \`textures.Albedo\`, \`cubeMaps.Studio\`, \`materials.Wood\`, \`audios.Click\`, \`models.Robot\`, \`animations.Run\`, \`vertexAnimations.HorseGallopVat\`, \`fonts.Title\`, or \`serializedData.Config\`. If the name already exists, the upload result returns \`skipped: true\` and the existing asset. Staged chunks/blobs are also swept lazily after about 24 hours. Model-family uploads enable meshoptimizer by default unless \`useMeshoptimizer\` is false.`,
44537
44549
  "14. Project tools: use `list_wave_project_templates` before `new_wave_project({ templateId? })`; use `list_wave_projects` before `rename_wave_project({ projectId, name })` or `open_wave_project({ projectId })`. Use `read_wave_project` to learn from example packs without replacing the current editor workspace: pass exact `projectId` from `list_wave_projects` for listed/saved projects, or pass a shared/published project `url` directly for silent URL reads. Shared URL reads support old `/waveStudio?share=<uuid>` links and new shared alias links; published URL reads support old/new `/p/<user>/<id>` links. Rename updates saved project display metadata only. New/open replace the live workspace. If there are unsaved changes they return `unsaved_changes` unless you save first or explicitly pass `discardUnsavedChanges: true`; only use exact ids returned by list tools for open/rename.",
44538
44550
  "15. `save_wave_project` quick-saves an existing saved project and ignores name/description. For a new unsaved project, pass name/description when available; otherwise Studio generates defaults and returns whether each field was defaulted.",
44539
44551
  "16. `share_wave_project` runs the same Share Project menu pipeline, returns a 30-day share `url`, and requires write pairing plus the signed-in share policy. Always send the returned `url` back to the user.",
@@ -44552,7 +44564,7 @@ var WAVE_MCP_CODING_GUARDRAIL_SUMMARY = [
44552
44564
  "4. Prefer natural, intent-preserving public APIs and aliases such as Actor, Prop, Cube, Sphere, waveMaterial, semantic directions, Animate/Seconds/DegreesPerSecond, and fluent WaveEngine DSLs.",
44553
44565
  `4a. ${WAVE_AUTHORING_CORE_RULES.hotReloadCallbackSafety} edit_wave_file/apply_wave_patch/create_wave_file preflight this rule and runtime bundling blocks violations before authored code runs.`,
44554
44566
  "4b. For model voxelization, route to `wave.model.voxelization`; use `model.voxelizing().relativeSize(0.05).surfaceOnly().onWorkerThread().usingCubes().asThinBatch().applyAsync()` only when async/worker authored code is explicitly acceptable, or `onMainThread().apply()` only for tiny local synchronous voxel work. Never use `.apply().then(...)` or Promise callback chains. Use `detectNear`, `getColorAt`, and `whenIndexClicked(index => voxelBatch.at(index).enlargeBy(1.2).done().commitBuffers())` for thin-batch voxel interaction. Do not use `voxelizeHeavy`, `voxelize({ voxelSize })`, `withVoxelSize`, `sharedBox`, or stale `atIndex`.",
44555
- "5. Resolve assets explicitly. Use category-first bare refs returned by `find_wave_assets_by_category` or alias `list_wave_assets_by_category`: models.X, textures.X, materials.X, audios.X, hdr.X, animations.X. Do not guess refs, raw paths, or infer absence from a capped list.",
44567
+ "5. Resolve assets explicitly. Use category-first bare refs returned by `find_wave_assets_by_category` or alias `list_wave_assets_by_category`: models.X, textures.X, materials.X, audios.X, hdr.X, animations.X, vertexAnimations.X. Do not guess refs, raw paths, or infer absence from a capped list.",
44556
44568
  "6. `project.assetrefs.ts`, `project.scene.ts`, `project.scenes.ts`, and `project.execution.ts` are Studio-managed read-only. `bootstrap.ts` is normally managed too; edit it only with a confident `managedFileEditReason` for world streaming/terrain provider, render/runtime backend, media consent/capture, external AI/TTS backend, scene/template baseline, pre-main baseline setup, or stale bootstrap API update to latest. Never edit bootstrap for asset loaders/manifests, instruments, scene registry, or execution manifest.",
44557
44569
  "7. Use safest VFS tool: read first, default to edit_wave_file for small one-file edits, let it auto-resolve baseHash, use apply_wave_patch({ operations }) with explicit baseHash for grouped/advanced work, and inspect skips/partials.",
44558
44570
  "8. For obby/platform tasks, controlled players use kinematic-controller authoring; moving platforms and hazards use rigid-body kinematic geometry/props plus transform/animate/current-code motion.",
@@ -44623,12 +44635,12 @@ var WAVE_MCP_FILE_CONTEXT_GUIDE = [
44623
44635
  "Wave Studio file-context rules:",
44624
44636
  "- Normal scene edit path: use the active `*/main.ts`, write against `myScene`, use bare asset refs, and do not edit Studio-managed generated files.",
44625
44637
  "- Studio-managed generated files are MCP read-only for agents: `project.assetrefs.ts`, `project.scene.ts`, `project.scenes.ts`, and `project.execution.ts`. `bootstrap.ts` / scene `*/bootstrap.ts` is normally Studio-managed too; edit it only when you can confidently pass `managedFileEditReason` as one of: `world_streaming_or_terrain_provider`, `render_profile_or_runtime_backend`, `media_consent_or_capture_plan`, `external_ai_or_tts_backend`, `scene_envelope_or_template_baseline`, `baseline_setup_before_user_main`, `stale_api_update_to_latest`. Never edit bootstrap for assets/loaders, instruments, scene registry, or execution manifest; Studio owns those.",
44626
- "- `main.ts` / scene `*/main.ts`: user scene authoring code. Prefer `myScene` for the active scene. Also available: `assetManager`, `waveEngine`, `waveStudio`, `models`, `gaussianSplats`, `fbxModels`, `animations`, `materials`, `guis`, `textures`, `audios`, `instruments`, `videos`, `hdr`, `cubeMaps`, `generatedModels`, `fonts`, `serializedData`, `terrains`, `fx`, `particles`.",
44638
+ "- `main.ts` / scene `*/main.ts`: user scene authoring code. Prefer `myScene` for the active scene. Also available: `assetManager`, `waveEngine`, `waveStudio`, `models`, `gaussianSplats`, `fbxModels`, `animations`, `vertexAnimations`, `materials`, `guis`, `textures`, `audios`, `instruments`, `videos`, `hdr`, `cubeMaps`, `generatedModels`, `fonts`, `serializedData`, `terrains`, `fx`, `particles`.",
44627
44639
  `- Studio also injects many authoring constants/functions as bare globals. ${WAVE_AUTHORING_BARE_GLOBALS_RULE} Do not add imports or guessed namespaces. Treat listed globals as examples and use local-SDK \`query_wave_api\` for the complete generated authoring surface. HTTP Gateway hides/retires skill/API lookup.`,
44628
44640
  "- Project code does not need to live in one monolith. Use `create_wave_file`, `rename_wave_file`, and `delete_wave_file` for VFS `.ts` modules and folders, for example `/actors/player.ts` or `/systems/movingPlatforms.ts`. New `.ts/.tsx` files are runnable source roots by default, so top-level scene code in them runs on Run/hot reload; pass `runnable:false` only for pure helper modules that should not execute on their own.",
44629
44641
  '- Studio VFS also supports non-code `.html` sketch files. Use `create_wave_file({ path: "/docs/diagram.html", content })` for Mermaid diagrams, charts, and lightweight docs; put Mermaid source inside `<div class="mermaid">...</div>`, not markdown fences. When that `.html` file is active, the editor/coding pane renders it as an HTML sketch and auto-loads Mermaid if `class="mermaid"` is present. HTML sketches must never replace the live engine preview iframe.',
44630
44642
  "- `list_wave_files` and `read_wave_file` return a full-file `contentHash`. Primary simple edit tool `edit_wave_file` can omit `baseHash`; Studio resolves the latest mirror hash and still performs browser-side stale-write checks. It accepts `edits:[{startLine,endLine,text}]` or `edits:[{rangeOffset,rangeLength,text}]` for one-file multi-edits. Use explicit `baseHash` for advanced `apply_wave_patch({ operations: [...] })` compact operations (`lineEdits`, `textEdits`, strict `searchReplace`, or `unifiedDiff`) and existing-file `writeFile` unless `forceOverwrite: true`. This hash is a cooperative stale-write check, not a security boundary. Prefer forgiving `edit_wave_file` over full-file `writeFile` when only a small span changes. Stale hashes and ambiguous replacements are skipped instead of guessed. `textEdits` offsets are zero-based UTF-16 offsets in the full file, even if you used a scoped line read; line edits use 1-based full-file line numbers. Scoped reads and line edits clamp oversized endLine to lineCount but still reject startLine beyond the file. If you need multiple compact changes in one file, use `edit_wave_file({ path, edits:[...] })` or combine them into one advanced patch operation; re-read between separate operations.",
44631
- "- Main-file asset refs should be bare: `models.Car`, `gaussianSplats.Room`, `textures.Grass`, `materials.Metal`, `animations.Idle`. Omit `ASSET_WAREHOUSE.` for authored code.",
44643
+ "- Main-file asset refs should be bare: `models.Car`, `gaussianSplats.Room`, `textures.Grass`, `materials.Metal`, `animations.Idle`, `vertexAnimations.HorseGallopVat`. Omit `ASSET_WAREHOUSE.` for authored code.",
44632
44644
  "- Asset facade split: existing asset inputs use typed refs; material authoring starts from `waveMaterial`; `assetManager` is for explicit generated-asset/asset-pipeline APIs named by a local SDK skill or API lookup, not the default place to invent new material or asset code.",
44633
44645
  "- Use `find_wave_assets_by_category({ category, query?, limit? })` to inspect the current live asset surface. Fill category from user intent first. It includes public assets, uploaded user assets, and project aliases, with `source` telling where each ref came from.",
44634
44646
  "- Wave Studio auto-maintains bootstrap/project asset/scene wiring for normal `main.ts` edits. Do not write or modify bootstrap or generated project registry files just to make an asset ref or scene entry available; use the returned bare refs in main code and let Studio sync boot/assets/scenes. Hot reload is the default preview path after code edits and can automatically upgrade its internal tier when new assets or bootstrap-surface changes require it.",
@@ -44683,13 +44695,13 @@ var WAVE_MCP_STUDIO_TOOL_GUIDE = [
44683
44695
  '- Local parity rule: WaveEngine Agent SDK `tools/list` mirrors the HTTP Gateway Studio-operation catalog, then adds local SDK lookup/session-discovery extras. Direct local live-session tools include VFS edits, assets/uploads, project save/open/new/read/share, preview run/hot reload/pause/resume, diagnostics, performance, screenshots, entity snapshots, and runtime markers. Local browser-backed calls wait directly for browser results. Only call `get_wave_command_result` if a tool returns `status:"pending"` plus `requestId`; on local it normally exists only for catalog parity and reports no local pending-command queue.',
44684
44696
  `- MCP topology: same-machine agents should run \`${WAVE3D_AGENT_SDK_START_COMMAND}\`, check /health, and update/restart SDK if version is stale, tools are missing, or SDK prints secrets; after restart recheck /health and tools/list. If restart happens after Copy-to-Agent, preserve MCP_TOKEN with \`${WAVE3D_AGENT_SDK_TOKEN_PRESERVING_START_COMMAND}\` using the current MCP_TOKEN value without printing it, otherwise the SDK may be healthy but unable to authorize the copied local pairing secret. Current SDK start reuses a current same-token peer, replaces verified stale/different-token SDK peers on localhost, and refuses to kill non-SDK port owners. Same-machine stale/missing tools/401-with-Gateway-success means repair local SDK first, not HTTP Gateway first. Same-machine HTTP Gateway is degraded fallback only after SDK cannot run, update, or adopt. Different-machine/cloud/sandbox agents should use \`MCP_HTTP_GATEWAY_FALLBACK_URL\` directly; starting WaveEngine Agent SDK there binds localhost beside the agent, not beside the user browser. Stale SDK/cache are not reasons to use HTTP Gateway fallback; wrong-machine localhost is a topology mismatch.`,
44685
44697
  `- MCP cache priorities: Priority 1 is active role/context cache: keep role, guardrails, authoring workflow, asset/VFS/hot-reload rules, prompt version, and prompt hash in active LLM context. Priority 2 is WaveEngine SDK Cache: production HTTP Gateway/local-SDK onboarding must not claim normal cached success until SDK cache is prepared or accept proof passes. If accept returns \`wave_engine_sdk_cache_not_ready\`, update/restart \`wave3d-agent-sdk\` or run \`${WAVE_MCP_CORPUS_CACHE_COMMAND_TEMPLATE}\`, then retry accept. If local cache cannot work because sandbox/no filesystem/no Node/npm/user refusal/refresh failure, explicitly accept degraded fallback with \`waveEngineSdkFallbackMode:"studio_ops_only"\`, a valid \`waveEngineSdkUnavailableReason\`, and \`studioOpsOnlyFallbackAccepted:true\`; warn user HTTP Gateway is Studio-ops-only and skill/API lookup requires local SDK/cache repair. This cache command reinstalls the package-bundled SDK locally; it is not WaveEngine Agent SDK transport. Never run it to switch MCP transport; never treat cache failure as local transport failure.`,
44686
- "- Main-file globals include `myScene`, `assetManager`, `waveEngine`, `waveStudio`, and direct asset maps such as `models`, `gaussianSplats`, `textures`, `materials`, `animations`, `audios`, `hdr`, `cubeMaps`, `fonts`, `serializedData`, `terrains`, `fx`, `particles`. Availability is not endorsement: choose the intent-owned facade/skill before using a global.",
44698
+ "- Main-file globals include `myScene`, `assetManager`, `waveEngine`, `waveStudio`, and direct asset maps such as `models`, `gaussianSplats`, `textures`, `materials`, `animations`, `vertexAnimations`, `audios`, `hdr`, `cubeMaps`, `fonts`, `serializedData`, `terrains`, `fx`, `particles`. Availability is not endorsement: choose the intent-owned facade/skill before using a global.",
44687
44699
  `- Bare authoring globals: common examples include ${WAVE_AUTHORING_COMMON_GLOBAL_EXAMPLES_TEXT}, \`waveMaterial\`, \`waveFx\`, \`waveValueCurve\`, and \`waveParam\`. Use them directly in \`main.ts\`; do not import or namespace-qualify them. If the task is unfamiliar, retrieve the relevant local-SDK \`wave.*\` skill first; for the full generated exact-global surface, call local-SDK \`query_wave_api\`.`,
44688
44700
  "- MCP VFS edit tools: primary tool is forgiving `edit_wave_file({ path, ... })`; it infers replaceLines from startLine/endLine, multi-edit from edits:[...], replaceText from oldText, and whole-file replace from text/content. It handles line-based edits, exact string changes, one-file edit arrays, whole-file replacement, omitted baseHash, common aliases, and oversized endLine clamping. Use `apply_wave_patch({ operations: [...] })` only for grouped/multi-file edits and advanced operations; a single operation is tolerated but operations:[...] is preferred. Simple edit tools can omit baseHash; advanced patch operations should pass it.",
44689
44701
  `- MCP hot-reload safety rule: ${WAVE_AUTHORING_CORE_RULES.hotReloadCallbackSafety} edit_wave_file, create_wave_file, and apply_wave_patch preflight this rule before writing.`,
44690
44702
  "- MCP generated-file rule: `project.assetrefs.ts`, `project.scene.ts`, `project.scenes.ts`, and `project.execution.ts` are Studio-managed read-only. `bootstrap.ts` / scene `*/bootstrap.ts` is normally managed too; edit it only when you can confidently pass `managedFileEditReason` as `world_streaming_or_terrain_provider` (Google Maps 3D tiles included), `render_profile_or_runtime_backend`, `media_consent_or_capture_plan`, `external_ai_or_tts_backend`, `scene_envelope_or_template_baseline`, `baseline_setup_before_user_main`, or `stale_api_update_to_latest`. Never edit bootstrap for asset manifests/loaders, instruments, scene registry, or execution manifest; Studio owns those.",
44691
44703
  '- MCP VFS file tools: `create_wave_file({ path, content, requestHotReload? })`, `rename_wave_file({ fromPath, toPath, requestHotReload? })`, and `delete_wave_file({ path, requestHotReload? })` are direct Operate tools for exact live VFS paths, including project `.ts` modules and `.html` sketch files. New `.ts/.tsx` files are standalone runnable source roots by default, so top-level scene code runs on Run/hot reload; pass `runnable:false` only for pure helper modules that should not execute on their own. For Mermaid/diagram/chart requests, create a `.html` file containing a block like `<div class="mermaid">flowchart TD\\n A --> B</div>`; active `.html` files render in the editor/coding pane as HTML sketches and auto-load Mermaid when `class="mermaid"` is present. HTML sketches must never replace the live engine preview iframe. On the final code edit, `awaitHotReload:true` implies hot reload and returns bounded runtime diagnostics in the same response. These tools manage VFS files, not uploaded asset-library blobs. If the user gives a vague target, call `list_wave_files`/`read_wave_file` or ask before mutating. Scene-root modules and owned helpers run in the Studio authoring context; keep shared helpers pure or parameterized, and keep live object ownership in feature files. Rename/move rewrites relative imports; delete is permanent unless you rewrite the file and refuses files still imported by other VFS code.',
44692
- "- MCP asset resolution rule: if code needs an existing asset argument, reuse an exact visible typed ref or call category-first asset discovery before editing: `find_wave_assets_by_category({ category, query?, sources?, limit? })`, alias `list_wave_assets_by_category`, alias `search_wave_assets_by_category`, or tolerant `list_wave_assets`. Fill `category` from user intent first: sound/audio -> `audios`, 3D object/character/prop -> `models`, material -> `materials`, image/texture -> `textures`, sky/HDR -> `hdr`, cube-map sky/environment -> `cubeMaps`, animation -> `animations`, JSON/CSV/YAML/XML/ROS data -> `serializedData`. It returns refs safe to use in authored code, ordered projectAlias -> user -> public. In `main.ts`, pass typed bare refs such as `models.X`, `textures.X`, `materials.X`, `audios.X`, `hdr.X`, `cubeMaps.X`, `animations.X`, `videos.X`, `fonts.X`, `serializedData.X`, or `terrains.X`; do not paste raw paths.",
44704
+ "- MCP asset resolution rule: if code needs an existing asset argument, reuse an exact visible typed ref or call category-first asset discovery before editing: `find_wave_assets_by_category({ category, query?, sources?, limit? })`, alias `list_wave_assets_by_category`, alias `search_wave_assets_by_category`, or tolerant `list_wave_assets`. Fill `category` from user intent first: sound/audio -> `audios`, 3D object/character/prop -> `models`, material -> `materials`, image/texture -> `textures`, sky/HDR -> `hdr`, cube-map sky/environment -> `cubeMaps`, skeletal animation -> `animations`, baked vertex/VAT animation -> `vertexAnimations`, JSON/CSV/YAML/XML/ROS data -> `serializedData`. It returns refs safe to use in authored code, ordered projectAlias -> user -> public. In `main.ts`, pass typed bare refs such as `models.X`, `textures.X`, `materials.X`, `audios.X`, `hdr.X`, `cubeMaps.X`, `animations.X`, `vertexAnimations.X`, `videos.X`, `fonts.X`, `serializedData.X`, or `terrains.X`; do not paste raw paths.",
44693
44705
  "- MCP asset-authoring facade rule: quoting or passing existing assets uses typed refs such as `models.X`, `textures.X`, `materials.X`, and `audios.X`; creating/configuring/forking/editing material handles starts from `waveMaterial` and `wave.material.authoring`; path-bound surfaces start from `wavePathSurface`; `assetManager` is reserved for exact low-level asset-pipeline/generated-asset APIs named by a local SDK skill or API lookup.",
44694
44706
  "- MCP material authoring rule: quoting an existing material uses `materials.X`; authoring a material handle uses `waveMaterial`. Do not call internal procedural material lifecycle methods such as `_sync(...)`, `_bindAutoSync(...)`, or `_release(...)` in authored code; apply procedural handles through `entity.useMaterial(...)`, geometry, terrain paint, or shader `.useTexture(...)`. `WaveMaterialAssetEditHandle.sync(assetManager)` remains the explicit commit step for intentional loaded-material asset edits.",
44695
44707
  `- MCP explorer asset tools: \`list_wave_explorer_assets({ query?, assetTypes?, limit? })\`, \`create_wave_asset_upload({ assetKind, filename, contentType?, sizeBytes })\`, \`commit_wave_asset_upload({ assetKind, uploadId, filename, contentType?, sizeBytes, useMeshoptimizer?, useKtx2Compression? })\`, \`get_wave_asset_upload_status({ uploadId, totalChunks? })\`, \`upload_wave_asset({ assetKind, filename, dataBase64? | dataUrl?, contentType?, useMeshoptimizer?, useKtx2Compression? })\`, \`stage_wave_asset_upload_chunk({ uploadId?, chunkIndex, totalChunks, dataBase64 })\`, \`commit_wave_asset_chunk_upload({ assetKind, uploadId, filename, contentType?, totalChunks, totalSizeBytes, useMeshoptimizer?, useKtx2Compression? })\`, \`abort_wave_asset_upload({ uploadId })\`, \`rename_wave_asset({ path, name })\`, and \`delete_wave_asset({ path })\` operate on uploaded user assets shown by the asset explorer. \`assetKind\` values come from the Wave Studio upload policy SSOT: ${getWaveStudioBridgeAssetUploadKindHelpText()}. Status and abort require the same write token, but can still run after the active Studio write grant expires. Read \`resultSummary\` first: asset tools report ASSET ... OK, ASSET ... FAILED, or ASSET ... PENDING in the same response.`,
@@ -44767,8 +44779,8 @@ var WAVE_MCP_TOOL_CATALOG_GUIDE = [
44767
44779
  "- Marker waypoint recipe: direct marker position/rotation questions are Observe and call `list_wave_runtime_markers` directly. When the user asks to use clicked/marked points in code, start a route with `marker.use` plus `code.author` or the fitting fast-lane code kind, then call `list_wave_runtime_markers`. Read the target file, use marker `worldPosition`/`worldRotation` as waypoint/path/placement inputs, and verify with screenshot or marker re-read. Retrieve a path/placement skill only when current code does not reveal the pattern.",
44768
44780
  "",
44769
44781
  "studio.assets - refs, uploads, and asset library:",
44770
- "- Asset resolution rule: before writing an asset-map input, reuse an exact ref already visible in code or call category-first asset discovery (`find_wave_assets_by_category`, alias `list_wave_assets_by_category`) with required `category`, semantic `query`, and small `limit`; do not invent `models.<asset>`, `textures.<asset>`, `materials.<asset>`, `audios.<asset>`, `hdr.<asset>`, `cubeMaps.<asset>`, or `animations.<asset>` keys from memory. Do not infer absence from a capped category list.",
44771
- "- Existing asset arguments should be typed bare refs in main files, such as `models.Robot`, `textures.Grass`, `materials.Wood`, `audios.Click`, `hdr.StudioSky`, `cubeMaps.studio`, `animations.Run`, `videos.Intro`, `fonts.Title`, `serializedData.UnitreePose`, or `terrains.Alpine`.",
44782
+ "- Asset resolution rule: before writing an asset-map input, reuse an exact ref already visible in code or call category-first asset discovery (`find_wave_assets_by_category`, alias `list_wave_assets_by_category`) with required `category`, semantic `query`, and small `limit`; do not invent `models.<asset>`, `textures.<asset>`, `materials.<asset>`, `audios.<asset>`, `hdr.<asset>`, `cubeMaps.<asset>`, `animations.<asset>`, or `vertexAnimations.<asset>` keys from memory. Do not infer absence from a capped category list.",
44783
+ "- Existing asset arguments should be typed bare refs in main files, such as `models.Robot`, `textures.Grass`, `materials.Wood`, `audios.Click`, `hdr.StudioSky`, `cubeMaps.studio`, `animations.Run`, `vertexAnimations.HorseGallopVat`, `videos.Intro`, `fonts.Title`, `serializedData.UnitreePose`, or `terrains.Alpine`.",
44772
44784
  "- Asset authoring facade split: quote existing assets as typed refs (`models.X`, `textures.X`, `materials.X`, `audios.X`, etc.); author material handles through `waveMaterial` and `wave.material.authoring`; use `assetManager` only for exact generated-asset/asset-pipeline APIs named by a local SDK Wave skill or API lookup.",
44773
44785
  '- `find_wave_assets_by_category`: category-first refs safe to write in code, such as `models.Robot`, `textures.Grass`, `materials.Wood`, `audios.Click`. Aliases: `list_wave_assets_by_category`, `search_wave_assets_by_category`, tolerant `list_wave_assets`. Examples: `{ category:"models", query:"sparrow", limit:50 }`, `{ category:"audios", query:"footstep", limit:50 }`, `{ category:"materials", query:"grass", limit:50 }`.',
44774
44786
  "- `list_wave_explorer_assets`: uploaded asset library metadata for management: path, URL, display/ref name, type, size. May be empty; not a fallback for built-in/public refs.",
@@ -45961,6 +45973,18 @@ function normalizeKnownDimensionsMm(value) {
45961
45973
  }
45962
45974
  return Object.keys(result).length > 0 ? result : null;
45963
45975
  }
45976
+ function duplicateStrings(items) {
45977
+ const seen = /* @__PURE__ */ new Set();
45978
+ const duplicates = /* @__PURE__ */ new Set();
45979
+ for (const item of items) {
45980
+ if (seen.has(item)) {
45981
+ duplicates.add(item);
45982
+ } else {
45983
+ seen.add(item);
45984
+ }
45985
+ }
45986
+ return [...duplicates];
45987
+ }
45964
45988
  function parseModelingJobArgs(args) {
45965
45989
  const sourcePrompt = normalizeOptionalString(args?.sourcePrompt) ?? normalizeOptionalString(args?.prompt) ?? normalizeOptionalString(args?.description);
45966
45990
  if (!sourcePrompt) {
@@ -45977,6 +46001,14 @@ function parseModelingJobArgs(args) {
45977
46001
  "`knownDimensionsMm` must be a JSON object with only JSON-safe values."
45978
46002
  );
45979
46003
  }
46004
+ const requiredParts = optionalStringArray(args?.requiredParts) ?? [];
46005
+ const duplicateRequiredParts = duplicateStrings(requiredParts);
46006
+ if (duplicateRequiredParts.length > 0) {
46007
+ return errorToolResult(
46008
+ "invalid_arguments",
46009
+ `\`requiredParts\` names must be unique because Wave getPart(name) requires unambiguous public part names. Duplicates: ${duplicateRequiredParts.join(", ")}.`
46010
+ );
46011
+ }
45980
46012
  return {
45981
46013
  assetName: sanitizeAssetName(rawAssetName),
45982
46014
  sourcePrompt,
@@ -45984,7 +46016,7 @@ function parseModelingJobArgs(args) {
45984
46016
  referenceImagePaths: optionalStringArray(args?.referenceImagePaths) ?? [],
45985
46017
  targetStyle: normalizeOptionalString(args?.targetStyle) ?? null,
45986
46018
  intendedUse: normalizeOptionalString(args?.intendedUse) ?? null,
45987
- requiredParts: optionalStringArray(args?.requiredParts) ?? [],
46019
+ requiredParts,
45988
46020
  knownDimensionsMm
45989
46021
  };
45990
46022
  }
@@ -45992,7 +46024,36 @@ function markdownList(items, emptyText) {
45992
46024
  if (items.length === 0) return `- ${emptyText}`;
45993
46025
  return items.map((item) => `- ${item}`).join("\n");
45994
46026
  }
46027
+ var WAVE_OBJECT_MODEL_PARTS_CONTRACT = `## WaveEngine objectModel SSOT contract
46028
+
46029
+ When requiredParts is non-empty, or the user asks for named/selectable/collidable/material-addressable parts, the GLB must carry Wave objectModel metadata. Mesh names, ordered mesh arrays, and per-mesh part metadata are not source of truth.
46030
+
46031
+ Required GLB shape for part-aware output:
46032
+
46033
+ - Add an empty/transform node named \`__wave_model_object_model\`; it must have no children.
46034
+ - Put \`waveModelObjectModel\` in that node's metadata/extras.
46035
+ - The value must be a valid WaveModelObjectModel JSON object:
46036
+ - \`version: 1\`
46037
+ - \`modelId\`: stable asset id/name
46038
+ - \`revision\`: stable revision string for this generated artifact
46039
+ - \`meshes\`: one record per render mesh with stable \`id\`, \`displayName\`, and \`order\`
46040
+ - \`parts\`: one record per user-facing part with stable \`id\`, public \`name\`, \`order\`, optional \`parentPartId\`, optional \`rotationPivot\`, optional \`visualFrame\`
46041
+ - \`meshPartBindings\`: explicit bindings from mesh id to part id with role \`visual\` or \`collision\`
46042
+ - \`parentPartId\` on child part records when parts have authored parent/child relationships
46043
+ - \`topology\`: include \`rootPartIds\` and \`joints: []\` only when a rig/joint topology is needed
46044
+ - \`materialSlots\` and \`materialBindings\`: canonical material targets when materials are meant to be changed by mesh or part
46045
+
46046
+ Rules:
46047
+
46048
+ - If user did not ask for parts, do not invent parts for every mesh. Output mesh-only GLB.
46049
+ - If a visual part contains multiple meshes, bind all meshes to the same part id.
46050
+ - Preserve authored pivots/origins as objectModel \`rotationPivot\` and \`visualFrame\`, not by baking them away.
46051
+ - Do not write old per-mesh part projection keys, legacy metadata part arrays, mesh-name-derived part ids, or positional part arrays.
46052
+ - Validate before upload: every required part name appears in \`objectModel.parts[].name\`, and every part-owned mesh has a matching \`meshPartBindings[]\` record.
46053
+ `;
45995
46054
  function buildModelingSupportFiles(input) {
46055
+ const requestedPartsText = input.requiredParts.length > 0 ? input.requiredParts.join(", ") : "none explicitly requested; keep output mesh-only unless the source request itself asks for named/selectable/collidable/material-addressable parts";
46056
+ const visiblePartsInstruction = input.requiredParts.length > 0 ? "- Named visible parts matching requiredParts exactly." : "- Mesh/object breakdown only; do not invent Wave parts unless the source request itself asks for named/selectable/collidable/material-addressable parts.";
45996
46057
  const briefJson = JSON.stringify({
45997
46058
  assetName: input.assetName,
45998
46059
  sourcePrompt: input.sourcePrompt,
@@ -46005,7 +46066,22 @@ function buildModelingSupportFiles(input) {
46005
46066
  outputContract: {
46006
46067
  preferredModelFile: `${input.assetName}.glb`,
46007
46068
  optionalCadFile: `${input.assetName}.step`,
46008
- waveStudioImport: "Use create_wave_asset_upload/upload_wave_asset after GLB exists, then author code with models.<assetName>."
46069
+ waveStudioImport: "Use create_wave_asset_upload/upload_wave_asset after GLB exists, then author code with models.<assetName>.",
46070
+ objectModelSSOT: input.requiredParts.length > 0 ? {
46071
+ required: true,
46072
+ envelopeNodeName: "__wave_model_object_model",
46073
+ envelopeMetadataKey: "waveModelObjectModel",
46074
+ forbiddenLegacyTruth: [
46075
+ "old per-mesh part projection keys",
46076
+ "legacy metadata part arrays",
46077
+ "mesh-name-derived part ids",
46078
+ "ordered mesh arrays as part truth"
46079
+ ]
46080
+ } : {
46081
+ required: false,
46082
+ conditionalRequirement: "Embed objectModel SSOT only if the source request itself asks for named/selectable/collidable/material-addressable parts.",
46083
+ rule: "Do not invent objectModel parts for raw multi-mesh GLB unless user explicitly requests parts."
46084
+ }
46009
46085
  }
46010
46086
  }, null, 2);
46011
46087
  const parameterTemplate = JSON.stringify({
@@ -46017,7 +46093,7 @@ function buildModelingSupportFiles(input) {
46017
46093
  overall_height: input.knownDimensionsMm?.overall_height ?? 500,
46018
46094
  bevel_radius: 12
46019
46095
  },
46020
- parts: input.requiredParts.length > 0 ? input.requiredParts.map((partName) => ({ name: partName, materialHint: "default" })) : [{ name: "body", materialHint: "default" }]
46096
+ parts: input.requiredParts.length > 0 ? input.requiredParts.map((partName) => ({ name: partName, materialHint: "default" })) : []
46021
46097
  }, null, 2);
46022
46098
  return [
46023
46099
  {
@@ -46045,8 +46121,9 @@ ${markdownList(input.referenceImagePaths, "No reference image paths provided.")}
46045
46121
  2. Fill \`parameters.template.json\`.
46046
46122
  3. Run \`python build_step.py parameters.template.json out\` after installing CadQuery/OCP locally.
46047
46123
  4. Convert the STEP/mesh result to GLB with your approved modeling pipeline.
46048
- 5. Upload the GLB through Wave Studio MCP asset upload tools.
46049
- 6. Author scene code with \`models.${input.assetName}\`.
46124
+ 5. If parts are requested, embed and validate the Wave objectModel SSOT contract before upload.
46125
+ 6. Upload the GLB through Wave Studio MCP asset upload tools.
46126
+ 7. Author scene code with \`models.${input.assetName}\`.
46050
46127
 
46051
46128
  ## Safety
46052
46129
 
@@ -46068,15 +46145,17 @@ Asset name: ${input.assetName}
46068
46145
  Request: ${input.sourcePrompt}
46069
46146
  Target style: ${input.targetStyle ?? "match source/reference"}
46070
46147
  Intended use: ${input.intendedUse ?? "WaveEngine scene asset"}
46071
- Required parts: ${input.requiredParts.length > 0 ? input.requiredParts.join(", ") : "infer minimal public-facing parts"}
46148
+ Required parts: ${requestedPartsText}
46149
+
46150
+ ${WAVE_OBJECT_MODEL_PARTS_CONTRACT}
46072
46151
 
46073
46152
  Use the screenshots/reference images as visual evidence. Return:
46074
46153
 
46075
46154
  - Orthographic front/side/top proportions.
46076
- - Named visible parts.
46155
+ ${visiblePartsInstruction}
46077
46156
  - Dimensions in millimeters.
46078
46157
  - Bevels, thickness, symmetry, repeating details.
46079
- - Material/color hints only. Do not invent private engine internals.
46158
+ - Material/color hints. Do not invent engine internals beyond the Wave objectModel SSOT contract.
46080
46159
  - A JSON parameter block compatible with parameters.template.json.
46081
46160
  `
46082
46161
  },
@@ -46098,7 +46177,6 @@ Use the screenshots/reference images as visual evidence. Return:
46098
46177
  },
46099
46178
  parts: {
46100
46179
  type: "array",
46101
- minItems: 1,
46102
46180
  items: {
46103
46181
  type: "object",
46104
46182
  required: ["name"],
@@ -46190,7 +46268,11 @@ if __name__ == "__main__":
46190
46268
 
46191
46269
  - Silhouette matches source screenshots from front/side/top.
46192
46270
  - Scale is correct for WaveEngine world use.
46193
- - Parts are named for future objectModel/part authoring where useful.
46271
+ - If parts were requested, GLB contains \`waveModelObjectModel\` on the \`__wave_model_object_model\` node metadata/extras.
46272
+ - If parts were requested, every required part is present in \`objectModel.parts[].name\`.
46273
+ - If parts were requested, every part mesh has explicit \`meshPartBindings[]\`; no per-mesh part metadata, legacy metadata part arrays, or mesh-name fallback is used.
46274
+ - If no parts were requested, raw multi-mesh GLB remains mesh-only and does not eagerly invent parts.
46275
+ - Part pivots/origins, if authored, survive as \`rotationPivot\` and \`visualFrame\`.
46194
46276
  - Material slots are clean and simple.
46195
46277
  - GLB loads in Wave Studio before code authoring.
46196
46278
  - Uploaded asset appears as \`models.${input.assetName}\`.
@@ -46223,7 +46305,9 @@ async function createWave3dModelingJobTool(args) {
46223
46305
  nextActions: [
46224
46306
  "Use cad-sheet-prompt.md plus screenshots/reference images to produce a CAD parameter spec.",
46225
46307
  "Fill parameters.template.json and run the Python scaffold only in a local modeling environment with CadQuery installed.",
46226
- "Convert generated model output to GLB, then upload with create_wave_asset_upload/upload_wave_asset.",
46308
+ "Convert generated model output to GLB.",
46309
+ "If parts are requested, embed and validate the Wave objectModel SSOT contract before upload.",
46310
+ "Upload with create_wave_asset_upload/upload_wave_asset.",
46227
46311
  `After upload, author WaveEngine scene code with models.${parsed.assetName}.`
46228
46312
  ],
46229
46313
  caveats: [
@@ -46241,7 +46325,7 @@ function buildWaveAssetListGuidance(input) {
46241
46325
  const hasFilters = hasQuery || hasBuckets || hasSources;
46242
46326
  const hasMore = input.summary.total > input.summary.returned;
46243
46327
  const guidance = [
46244
- "Use category-first asset discovery for code-safe refs such as models.X, textures.X, materials.X, audios.X, hdr.X, cubeMaps.X, and animations.X. Callable names: `find_wave_assets_by_category`, `list_wave_assets_by_category`, `search_wave_assets_by_category`, or tolerant `list_wave_assets`.",
46328
+ "Use category-first asset discovery for code-safe refs such as models.X, textures.X, materials.X, audios.X, hdr.X, cubeMaps.X, animations.X, and vertexAnimations.X. Callable names: `find_wave_assets_by_category`, `list_wave_assets_by_category`, `search_wave_assets_by_category`, or tolerant `list_wave_assets`.",
46245
46329
  "Choose category from user intent first, then search semantically with `query`; do not browse a broad slice and infer absence."
46246
46330
  ];
46247
46331
  if (hasMore && !hasQuery) {
@@ -46278,7 +46362,7 @@ function buildWaveExplorerAssetListGuidance(input) {
46278
46362
  const hasMore = input.summary.total > input.summary.returned;
46279
46363
  const guidance = [
46280
46364
  "`list_wave_explorer_assets` is for uploaded user-asset management metadata: path, URL, size, display/ref name, rename, and delete.",
46281
- "It is not the fallback for built-in/public code refs. Use category-first asset discovery (`find_wave_assets_by_category` or alias `list_wave_assets_by_category`) when code needs models.X, textures.X, materials.X, audios.X, hdr.X, cubeMaps.X, or animations.X."
46365
+ "It is not the fallback for built-in/public code refs. Use category-first asset discovery (`find_wave_assets_by_category` or alias `list_wave_assets_by_category`) when code needs models.X, textures.X, materials.X, audios.X, hdr.X, cubeMaps.X, animations.X, or vertexAnimations.X."
46282
46366
  ];
46283
46367
  if (input.summary.total === 0 && !hasQuery && !hasAssetTypes) {
46284
46368
  guidance.push("Empty explorer does not mean no code assets exist; it only means this uploaded-user library view has no returned items.");
@@ -47982,7 +48066,7 @@ var ASSET_CODE_REF_DISCOVERY_INPUT_SCHEMA = {
47982
48066
  properties: {
47983
48067
  category: {
47984
48068
  type: "string",
47985
- description: `Preferred asset category or alias. Use user intent to fill this first. Supported categories/aliases from Wave Studio asset SSOT: ${ASSET_CATEGORY_HELP}. Examples: sound/audio -> audios, 3D model/character -> models, material -> materials, texture/image -> textures, HDR sky -> hdr, cube-map sky/environment -> cubeMaps, animation -> animations.`
48069
+ description: `Preferred asset category or alias. Use user intent to fill this first. Supported categories/aliases from Wave Studio asset SSOT: ${ASSET_CATEGORY_HELP}. Examples: sound/audio -> audios, 3D model/character -> models, material -> materials, texture/image -> textures, HDR sky -> hdr, cube-map sky/environment -> cubeMaps, skeletal animation -> animations, baked vertex/VAT animation -> vertexAnimations.`
47986
48070
  },
47987
48071
  bucket: {
47988
48072
  type: "string",
@@ -48712,7 +48796,7 @@ function buildHostedWaveStudioMcpToolDefinitions() {
48712
48796
  },
48713
48797
  {
48714
48798
  name: "find_wave_assets_by_category",
48715
- description: `[studio.assets] Canonical category-first discovery for code refs. Use when code needs an existing asset: choose an asset category from the user intent first (model/sound/material/texture/sky/animation/etc.), then search the paired Wave Studio asset surface: public assets, uploaded user assets, and project aliases. Preferred shape: { category:"materials", query:"grass", limit:50 }. Friendly aliases \`list_wave_assets_by_category\`, \`search_wave_assets_by_category\`, and \`list_wave_assets\` route here. Returned bare refs are safe in code, e.g. models.Car, textures.Grass, materials.Wood, audios.Click, hdr.Sky, animations.Run. The category-filtered response can still be capped; do not infer absence without semantic query refinement.${BROWSER_COMMAND_PENDING_NOTE}`,
48799
+ description: `[studio.assets] Canonical category-first discovery for code refs. Use when code needs an existing asset: choose an asset category from the user intent first (model/sound/material/texture/sky/animation/VAT/etc.), then search the paired Wave Studio asset surface: public assets, uploaded user assets, and project aliases. Preferred shape: { category:"materials", query:"grass", limit:50 }. Friendly aliases \`list_wave_assets_by_category\`, \`search_wave_assets_by_category\`, and \`list_wave_assets\` route here. Returned bare refs are safe in code, e.g. models.Car, textures.Grass, materials.Wood, audios.Click, hdr.Sky, animations.Run, vertexAnimations.HorseGallopVat. The category-filtered response can still be capped; do not infer absence without semantic query refinement.${BROWSER_COMMAND_PENDING_NOTE}`,
48716
48800
  inputSchema: ASSET_CODE_REF_DISCOVERY_INPUT_SCHEMA
48717
48801
  },
48718
48802
  {
@@ -48759,7 +48843,7 @@ function buildHostedWaveStudioMcpToolDefinitions() {
48759
48843
  },
48760
48844
  {
48761
48845
  name: "upload_wave_asset",
48762
- description: `[studio.assets] Small inline upload only: upload bytes already loaded by the agent as base64/data URL. This tool does not read local paths. Upload decision tree: tiny bytes already in memory -> upload_wave_asset; local file path/normal size -> create_wave_asset_upload + raw PUT + commit_wave_asset_upload; direct_upload_unavailable or chunk-only environment -> stage_wave_asset_upload_chunk + commit_wave_asset_chunk_upload. assetKind values come from the Wave Studio upload policy SSOT: ${BRIDGE_ASSET_UPLOAD_KIND_HELP}. Meshoptimizer defaults on for model-family uploads only; useMeshoptimizer is ignored for non-model assets unless explicitly supported by the browser pipeline. Pass exactly one of dataBase64 or dataUrl. Returns typed refs such as textures.Albedo, cubeMaps.Studio, materials.Wood, audios.Click, models.Robot, animations.Run, fonts.Title, or serializedData.Config.${WRITE_PAIRING_REQUIRED_NOTE}${BROWSER_COMMAND_PENDING_NOTE}`,
48846
+ description: `[studio.assets] Small inline upload only: upload bytes already loaded by the agent as base64/data URL. This tool does not read local paths. Upload decision tree: tiny bytes already in memory -> upload_wave_asset; local file path/normal size -> create_wave_asset_upload + raw PUT + commit_wave_asset_upload; direct_upload_unavailable or chunk-only environment -> stage_wave_asset_upload_chunk + commit_wave_asset_chunk_upload. assetKind values come from the Wave Studio upload policy SSOT: ${BRIDGE_ASSET_UPLOAD_KIND_HELP}. Meshoptimizer defaults on for model-family uploads only; useMeshoptimizer is ignored for non-model assets unless explicitly supported by the browser pipeline. Pass exactly one of dataBase64 or dataUrl. Returns typed refs such as textures.Albedo, cubeMaps.Studio, materials.Wood, audios.Click, models.Robot, animations.Run, vertexAnimations.HorseGallopVat, fonts.Title, or serializedData.Config.${WRITE_PAIRING_REQUIRED_NOTE}${BROWSER_COMMAND_PENDING_NOTE}`,
48763
48847
  inputSchema: {
48764
48848
  type: "object",
48765
48849
  properties: {
@@ -50018,7 +50102,7 @@ function getReadToolDefinitions() {
50018
50102
  },
50019
50103
  {
50020
50104
  name: "create_wave_3d_modeling_job",
50021
- description: "[wave.modeling] Create a local SDK 3D-modeling job scaffold from a prompt and optional screenshots/reference image paths. Writes README, CAD prompt, JSON parameter template/schema, Python CadQuery STEP scaffold, and validation checklist into a temp job folder. Does not generate/upload a GLB by itself; use asset upload tools after a real model file exists. Aliases: generate_wave_3d_model, create_wave_3d_model, create_wave_3d_model_from_screenshots.",
50105
+ description: "[wave.modeling] Create a local SDK 3D-modeling job scaffold from a prompt and optional screenshots/reference image paths. Writes README, CAD prompt, JSON parameter template/schema, Python CadQuery STEP scaffold, and validation checklist into a temp job folder. Does not generate/upload a GLB by itself; use asset upload tools after a real model file exists. If requiredParts is supplied, the resulting GLB must embed Wave objectModel SSOT metadata via waveModelObjectModel on a __wave_model_object_model node; raw mesh names, per-mesh part metadata, legacy metadata part arrays, or positional mesh arrays are not part truth. Aliases: generate_wave_3d_model, create_wave_3d_model, create_wave_3d_model_from_screenshots.",
50022
50106
  inputSchema: {
50023
50107
  type: "object",
50024
50108
  properties: {
@@ -50059,7 +50143,7 @@ function getReadToolDefinitions() {
50059
50143
  requiredParts: {
50060
50144
  type: "array",
50061
50145
  items: { type: "string" },
50062
- description: "Optional named visible parts the generated model should preserve."
50146
+ description: "Optional public part names the generated GLB must preserve in objectModel SSOT. When non-empty, model output must include waveModelObjectModel on a __wave_model_object_model node with parts, meshPartBindings, parentPartId/topology/material data as needed, and no per-mesh part metadata projection keys."
50063
50147
  },
50064
50148
  knownDimensionsMm: {
50065
50149
  type: "object",
@@ -51050,7 +51134,7 @@ async function callReadTool(name, args, context) {
51050
51134
  "studio.preview: hot_reload_wave_preview (alias: hotreload_wave_preview), run_wave_preview (alias: run_project), pause_wave_preview (alias: pause_wave_engine), resume_wave_preview (alias: resume_wave_engine), get_wave_runtime_diagnostics (alias: get_wave_errors), get_wave_runtime_performance_snapshot (alias: get_wave_runtime_performance)",
51051
51135
  "studio.capture: capture_wave_screenshot (alias: get_wave_screenshot), get_wave_runtime_entity_snapshot (alias: get_wave_entity_snapshot), list_wave_runtime_markers (alias: list_wave_markers)",
51052
51136
  "wave.authoring: list_wave_skill_families, query_wave_skills, get_wave_skill, query_wave_api",
51053
- "wave.modeling: create_wave_3d_modeling_job (aliases: generate_wave_3d_model, create_wave_3d_model, create_wave_3d_model_from_screenshots) creates local SDK support files; upload generated GLB later with asset tools"
51137
+ "wave.modeling: create_wave_3d_modeling_job (aliases: generate_wave_3d_model, create_wave_3d_model, create_wave_3d_model_from_screenshots) creates local SDK support files; if parts are requested the generated GLB must embed waveModelObjectModel on a __wave_model_object_model node before upload"
51054
51138
  ],
51055
51139
  rules: [
51056
51140
  "studio.* labels are categories, not callable tools.",
@@ -3,6 +3,6 @@
3
3
  Bundled public-safe WaveEngine SDK lookup cache for wave3d-agent-sdk.
4
4
  Generated from sanitized public API/skill corpus during package build.
5
5
 
6
- cacheKey: 2026-06-24.4.wMh4twvnrJPgyEgJhV6QtcSQvoZClKr3
7
- bundleHash: wMh4twvnrJPgyEgJhV6QtcSQvoZClKr3
8
- zip: wave-engine-sdk-2026-06-24.4.wMh4twvnrJPgyEgJhV6QtcSQvoZClKr3.zip
6
+ cacheKey: 2026-06-24.4.63mahXl1wJFsVypHTa3YZmbYXIrToIkG
7
+ bundleHash: 63mahXl1wJFsVypHTa3YZmbYXIrToIkG
8
+ zip: wave-engine-sdk-2026-06-24.4.63mahXl1wJFsVypHTa3YZmbYXIrToIkG.zip
@@ -1,21 +1,21 @@
1
1
  {
2
- "version": "2026-06-24.4.wMh4twvnrJPgyEgJhV6QtcSQvoZClKr3",
2
+ "version": "2026-06-24.4.63mahXl1wJFsVypHTa3YZmbYXIrToIkG",
3
3
  "formatVersion": "2026-06-24.4",
4
- "cacheKey": "2026-06-24.4.wMh4twvnrJPgyEgJhV6QtcSQvoZClKr3",
5
- "bundleFileName": "wave-engine-sdk-2026-06-24.4.wMh4twvnrJPgyEgJhV6QtcSQvoZClKr3.zip",
6
- "bundleHash": "wMh4twvnrJPgyEgJhV6QtcSQvoZClKr3",
4
+ "cacheKey": "2026-06-24.4.63mahXl1wJFsVypHTa3YZmbYXIrToIkG",
5
+ "bundleFileName": "wave-engine-sdk-2026-06-24.4.63mahXl1wJFsVypHTa3YZmbYXIrToIkG.zip",
6
+ "bundleHash": "63mahXl1wJFsVypHTa3YZmbYXIrToIkG",
7
7
  "generatedAt": "2026-06-06T00:00:00.000Z",
8
8
  "sourceVersions": {
9
9
  "onboarding": {
10
10
  "promptVersion": "2026-06-22.1",
11
- "promptHash": "2lzzgYNUy3U2WxPm5UY9z3ZiaUWUlh-Y"
11
+ "promptHash": "jvKiC2UCRvVbpVc7IGen5RvQk3V9vRA-"
12
12
  },
13
13
  "apiHandbook": {
14
14
  "version": "1",
15
- "contentHash": "d59512be9755b0ae"
15
+ "contentHash": "58fdedcd747f52b9"
16
16
  },
17
- "waveSkillCorpusHash": "dcHw5Ebcnx59z7qt9kfN_G23nlxvZSqi",
18
- "sdkLookupCorpusHash": "chkQiqOkodizLUk-HrdoQ1HXd428XP7k"
17
+ "waveSkillCorpusHash": "ol6UwQmeF1EZGOW3uz8NWVzESWOrkc7P",
18
+ "sdkLookupCorpusHash": "ZJvWnfNdCRcoLSwB6tz3ehkJzGGYeTVd"
19
19
  },
20
20
  "cacheContract": {
21
21
  "llmContextCacheOnly": [
@@ -35,14 +35,14 @@
35
35
  "searchDocuments"
36
36
  ],
37
37
  "rule": "Priority 1 always-on sections must stay in LLM chat/system context. The WaveEngine SDK local cache is public-safe retrieval data, never the only memory for core policy.",
38
- "defaultRefreshCommand": "npx -y wave3d-agent-sdk@0.2.14 cache refresh",
38
+ "defaultRefreshCommand": "npx -y wave3d-agent-sdk@0.2.16 cache refresh",
39
39
  "refreshRule": "When using WaveEngine SDK local cache, compare cacheKey, bundleHash, and sourceVersions before trusting local lookup. If any value differs, update the SDK package or reinstall its bundled SDK cache and rebuild local indexes. Do not fetch a remote SDK zip.",
40
40
  "onlineFallback": "HTTP Gateway does not provide cloud API lookup. If local Node/npm or cache is refused/unavailable, use only concrete Studio operations and already-known code; repair the local WaveEngine SDK before unfamiliar API authoring."
41
41
  },
42
42
  "corpus": {
43
43
  "skillCount": 67,
44
- "apiEntryCount": 4257,
45
- "apiMethodGroupCount": 4520,
44
+ "apiEntryCount": 4260,
45
+ "apiMethodGroupCount": 4522,
46
46
  "apiInheritanceCount": 741
47
47
  },
48
48
  "files": [
@@ -51,14 +51,14 @@
51
51
  "mediaType": "application/json",
52
52
  "role": "lookup-guide",
53
53
  "bytes": 1311,
54
- "hash": "t7FXq-o34BD84aetwe5v7IFwq1V4jg9l"
54
+ "hash": "YeAaiCkYLuKoMCDXE2XQneoonBtuzAjQ"
55
55
  },
56
56
  {
57
57
  "path": "skills/wave-skills.jsonl",
58
58
  "mediaType": "application/jsonl",
59
59
  "role": "skill-corpus",
60
- "bytes": 559047,
61
- "hash": "kpe36hRxZfjMfHU5cKZvjamB0KC8DQ7K"
60
+ "bytes": 559362,
61
+ "hash": "qBYj0pNBjtFbA6NPXOeEs8JzOJeoKH4j"
62
62
  },
63
63
  {
64
64
  "path": "skills/foundations.jsonl",
@@ -78,15 +78,15 @@
78
78
  "path": "api/entries.jsonl",
79
79
  "mediaType": "application/jsonl",
80
80
  "role": "api-corpus",
81
- "bytes": 4219479,
82
- "hash": "5e3mI73T35gOyU-6ufdk317kSedy3nHi"
81
+ "bytes": 4221610,
82
+ "hash": "AVX0mRAkXs-jpLsVTwD5x8NGX5U_ApJb"
83
83
  },
84
84
  {
85
85
  "path": "api/method-groups.jsonl",
86
86
  "mediaType": "application/jsonl",
87
87
  "role": "api-corpus",
88
- "bytes": 1420068,
89
- "hash": "ZLgLqDrvbF1qO5JitaCM9j_lROa2TfZu"
88
+ "bytes": 1420909,
89
+ "hash": "zIVI7FTFXfNe6NqVJmVtqJty_ybf92A-"
90
90
  },
91
91
  {
92
92
  "path": "api/inheritance.jsonl",
@@ -100,14 +100,14 @@
100
100
  "mediaType": "application/json",
101
101
  "role": "api-corpus",
102
102
  "bytes": 219,
103
- "hash": "ENc3SeS9IYG6suD3rz4aJv0z3dfE8RaT"
103
+ "hash": "IkwK7b__4lrVlSlDL5-M2uDiZqcLrpy_"
104
104
  },
105
105
  {
106
106
  "path": "search/search-documents.jsonl",
107
107
  "mediaType": "application/jsonl",
108
108
  "role": "search-index",
109
- "bytes": 3976607,
110
- "hash": "e2h7kHS3b6nNtSpRIze7eB6j03lBddXQ"
109
+ "bytes": 3978654,
110
+ "hash": "QLsswU10LbjXeHtgS5PziZZ9sHlOBCY4"
111
111
  },
112
112
  {
113
113
  "path": "README.md",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave3d-agent-sdk",
3
- "version": "0.2.14",
3
+ "version": "0.2.16",
4
4
  "description": "WaveEngine Agent SDK for same-machine Wave Studio MCP plus bundled WaveEngine lookup.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",