@dreamerbird/camera-studio 0.2.0 → 0.3.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 (126) hide show
  1. package/dist/CameraScene.d.ts +1 -1
  2. package/dist/CameraScene.d.ts.map +1 -1
  3. package/dist/CameraScene.js +36 -6
  4. package/dist/PlacementManager.d.ts +15 -1
  5. package/dist/PlacementManager.d.ts.map +1 -1
  6. package/dist/PlacementManager.js +123 -14
  7. package/dist/agent/api.d.ts +5 -0
  8. package/dist/agent/api.d.ts.map +1 -1
  9. package/dist/agent/api.js +25 -0
  10. package/dist/agent/api.test.js +75 -1
  11. package/dist/agent/commands/assets.d.ts +5 -0
  12. package/dist/agent/commands/assets.d.ts.map +1 -1
  13. package/dist/agent/commands/assets.js +93 -21
  14. package/dist/agent/commands/assets.test.js +53 -0
  15. package/dist/agent/commands/materials.d.ts +18 -0
  16. package/dist/agent/commands/materials.d.ts.map +1 -0
  17. package/dist/agent/commands/materials.js +192 -0
  18. package/dist/agent/commands/materials.test.d.ts +2 -0
  19. package/dist/agent/commands/materials.test.d.ts.map +1 -0
  20. package/dist/agent/commands/materials.test.js +294 -0
  21. package/dist/agent/commands/modelRecovery.test.d.ts +2 -0
  22. package/dist/agent/commands/modelRecovery.test.d.ts.map +1 -0
  23. package/dist/agent/commands/modelRecovery.test.js +122 -0
  24. package/dist/agent/commands/models.d.ts +13 -0
  25. package/dist/agent/commands/models.d.ts.map +1 -1
  26. package/dist/agent/commands/models.js +98 -1
  27. package/dist/agent/commands/primitives.d.ts +27 -0
  28. package/dist/agent/commands/primitives.d.ts.map +1 -0
  29. package/dist/agent/commands/primitives.js +117 -0
  30. package/dist/agent/commands/primitives.test.d.ts +2 -0
  31. package/dist/agent/commands/primitives.test.d.ts.map +1 -0
  32. package/dist/agent/commands/primitives.test.js +135 -0
  33. package/dist/agent/expectedCommands.d.ts +1 -1
  34. package/dist/agent/expectedCommands.d.ts.map +1 -1
  35. package/dist/agent/expectedCommands.js +6 -0
  36. package/dist/agent/propAccess.d.ts +2 -0
  37. package/dist/agent/propAccess.d.ts.map +1 -1
  38. package/dist/agent/propAccess.js +21 -0
  39. package/dist/agent/registerCommands.d.ts.map +1 -1
  40. package/dist/agent/registerCommands.js +5 -1
  41. package/dist/agent/runtime/objectRuntime.d.ts +2 -0
  42. package/dist/agent/runtime/objectRuntime.d.ts.map +1 -1
  43. package/dist/agent/runtime/objectRuntime.js +15 -1
  44. package/dist/agent/runtime.d.ts +1 -0
  45. package/dist/agent/runtime.d.ts.map +1 -1
  46. package/dist/agent/runtime.js +2 -0
  47. package/dist/assetLibrary/dispose.d.ts +4 -2
  48. package/dist/assetLibrary/dispose.d.ts.map +1 -1
  49. package/dist/assetLibrary/dispose.js +7 -5
  50. package/dist/assetLibrary/gltfLoader.d.ts +2 -1
  51. package/dist/assetLibrary/gltfLoader.d.ts.map +1 -1
  52. package/dist/assetLibrary/gltfLoader.js +2 -2
  53. package/dist/assetLibrary/gltfResourceSet.d.ts +6 -0
  54. package/dist/assetLibrary/gltfResourceSet.d.ts.map +1 -0
  55. package/dist/assetLibrary/gltfResourceSet.js +27 -0
  56. package/dist/assetLibrary/gltfResourceSet.test.d.ts +2 -0
  57. package/dist/assetLibrary/gltfResourceSet.test.d.ts.map +1 -0
  58. package/dist/assetLibrary/gltfResourceSet.test.js +40 -0
  59. package/dist/assetLibrary/importModelFile.d.ts +5 -0
  60. package/dist/assetLibrary/importModelFile.d.ts.map +1 -1
  61. package/dist/assetLibrary/importModelFile.js +3 -16
  62. package/dist/assetLibrary/importModelFiles.d.ts +15 -0
  63. package/dist/assetLibrary/importModelFiles.d.ts.map +1 -0
  64. package/dist/assetLibrary/importModelFiles.js +58 -0
  65. package/dist/assetLibrary/importModelFiles.test.d.ts +2 -0
  66. package/dist/assetLibrary/importModelFiles.test.d.ts.map +1 -0
  67. package/dist/assetLibrary/importModelFiles.test.js +217 -0
  68. package/dist/assetLibrary/importPipeline.d.ts +15 -1
  69. package/dist/assetLibrary/importPipeline.d.ts.map +1 -1
  70. package/dist/assetLibrary/importPipeline.js +74 -38
  71. package/dist/assetLibrary/importPipeline.test.js +25 -0
  72. package/dist/assetLibrary/library.d.ts +1 -0
  73. package/dist/assetLibrary/library.d.ts.map +1 -1
  74. package/dist/assetLibrary/library.js +22 -1
  75. package/dist/assetLibrary/library.test.js +76 -0
  76. package/dist/bootstrap.d.ts +2 -1
  77. package/dist/bootstrap.d.ts.map +1 -1
  78. package/dist/bootstrap.js +69 -7
  79. package/dist/bootstrap.test.js +111 -0
  80. package/dist/config.d.ts +10 -1
  81. package/dist/config.d.ts.map +1 -1
  82. package/dist/hostFlows.d.ts +1 -0
  83. package/dist/hostFlows.d.ts.map +1 -1
  84. package/dist/hostFlows.js +9 -0
  85. package/dist/index.d.ts +10 -1
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +6 -1
  88. package/dist/materials/modelMaterials.d.ts +19 -0
  89. package/dist/materials/modelMaterials.d.ts.map +1 -0
  90. package/dist/materials/modelMaterials.js +253 -0
  91. package/dist/materials/modelMaterials.test.d.ts +2 -0
  92. package/dist/materials/modelMaterials.test.d.ts.map +1 -0
  93. package/dist/materials/modelMaterials.test.js +188 -0
  94. package/dist/materials/types.d.ts +20 -0
  95. package/dist/materials/types.d.ts.map +1 -0
  96. package/dist/materials/types.js +1 -0
  97. package/dist/materials/useModelMaterials.d.ts +10 -0
  98. package/dist/materials/useModelMaterials.d.ts.map +1 -0
  99. package/dist/materials/useModelMaterials.js +26 -0
  100. package/dist/materials/useModelMaterials.test.d.ts +2 -0
  101. package/dist/materials/useModelMaterials.test.d.ts.map +1 -0
  102. package/dist/materials/useModelMaterials.test.js +75 -0
  103. package/dist/poses.d.ts +38 -0
  104. package/dist/poses.d.ts.map +1 -0
  105. package/dist/poses.js +41 -0
  106. package/dist/poses.test.d.ts +2 -0
  107. package/dist/poses.test.d.ts.map +1 -0
  108. package/dist/poses.test.js +38 -0
  109. package/dist/primitives.d.ts +5 -0
  110. package/dist/primitives.d.ts.map +1 -0
  111. package/dist/primitives.js +15 -0
  112. package/dist/primitives.test.d.ts +2 -0
  113. package/dist/primitives.test.d.ts.map +1 -0
  114. package/dist/primitives.test.js +27 -0
  115. package/dist/reset.realStudio.test.d.ts +2 -0
  116. package/dist/reset.realStudio.test.d.ts.map +1 -0
  117. package/dist/reset.realStudio.test.js +60 -0
  118. package/dist/studioRoot.d.ts +4 -0
  119. package/dist/studioRoot.d.ts.map +1 -0
  120. package/dist/studioRoot.js +36 -0
  121. package/dist/studioRoot.test.d.ts +2 -0
  122. package/dist/studioRoot.test.d.ts.map +1 -0
  123. package/dist/studioRoot.test.js +62 -0
  124. package/dist/useCameraStudio.d.ts.map +1 -1
  125. package/dist/useCameraStudio.js +3 -2
  126. package/package.json +9 -1
@@ -25,7 +25,7 @@ export declare function captureAnchorSeed(mainCam: ISheetObject<any> | undefined
25
25
  * UI 装配可配见 ./uiConfig:停靠框 portal 容器 / z-index 基准 / 语言
26
26
  * (宿主已包 I18nProvider 时语言以宿主为准,ui.locale 仅自包时生效)。
27
27
  */
28
- export declare function CameraScene({ project, onFlows, onError }: CameraSceneProps): React.JSX.Element;
28
+ export declare function CameraScene({ project, onFlows, onError, includeDemoModel, }: CameraSceneProps): React.JSX.Element;
29
29
  /**
30
30
  * i18n 嵌套判定(spec §7):宿主树已包 studio 的 I18nProvider →
31
31
  * 原样渲染,语言以宿主为准(ui.locale 不生效);否则自包一层,
@@ -1 +1 @@
1
- {"version":3,"file":"CameraScene.d.ts","sourceRoot":"","sources":["../src/CameraScene.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAiB,YAAY,EAAC,MAAM,mBAAmB,CAAA;AACnE,OAAO,KASN,MAAM,OAAO,CAAA;AAsDd,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,mBAAmB,CAAA;AAiBjD,OAAO,KAAK,EAAc,UAAU,EAAC,MAAM,kBAAkB,CAAA;AAyD7D,OAAO,KAAK,EAAC,WAAW,EAAe,MAAM,aAAa,CAAA;AAG1D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,UAAU,CAAA;AAwmB9C;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,GAAG,SAAS,GACrC,UAAU,GAAG,SAAS,CAMxB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,GAAG,SAAS,GACrC,UAAU,CAcZ;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,EAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAC,EAAE,gBAAgB,qBAijDxE;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,EAAC,QAAQ,EAAC,EAAE;IAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAC,qBAIpE;AAuFD,8BAA8B;AAC9B,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,OAAO,GACR,EAAE;IACD,KAAK,EAAE,WAAW,CAAA;IAClB,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,IAAI,CAAA;CACnC,QAOA"}
1
+ {"version":3,"file":"CameraScene.d.ts","sourceRoot":"","sources":["../src/CameraScene.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAiB,YAAY,EAAC,MAAM,mBAAmB,CAAA;AACnE,OAAO,KASN,MAAM,OAAO,CAAA;AAsDd,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,mBAAmB,CAAA;AAiBjD,OAAO,KAAK,EAAc,UAAU,EAAC,MAAM,kBAAkB,CAAA;AA4D7D,OAAO,KAAK,EAAC,WAAW,EAAe,MAAM,aAAa,CAAA;AAG1D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,UAAU,CAAA;AAwmB9C;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,GAAG,SAAS,GACrC,UAAU,GAAG,SAAS,CAMxB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,GAAG,SAAS,GACrC,UAAU,CAcZ;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,OAAO,EACP,OAAO,EACP,gBAAuB,GACxB,EAAE,gBAAgB,qBAolDlB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,EAAC,QAAQ,EAAC,EAAE;IAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAC,qBAIpE;AAuFD,8BAA8B;AAC9B,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,OAAO,GACR,EAAE;IACD,KAAK,EAAE,WAAW,CAAA;IAClB,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,IAAI,CAAA;CACnC,QAOA"}
@@ -46,7 +46,7 @@ import { createSceneExportController, registerSceneExportController, } from './a
46
46
  import { rigIdOf, collectBoneNames } from './assetLibrary/rig';
47
47
  import { cameraOutlineMenuExtensionId, cameraOutlineObjectMenu, setCameraOutlineMenuCtx, } from './outlineObjectMenu';
48
48
  import { pruneObjectFromOutlineCollections } from '@dreamerbird/studio/panels/OutlinePanel/outlineOps/stateOps';
49
- import { createHostFlows, setDropPointContext, setHostFlowsHandle, setPlacingSnapshot, } from './hostFlows';
49
+ import { createHostFlows, dropPointFromClient, isDropPointInsideCanvas, setDropPointContext, setHostFlowsHandle, setPlacingSnapshot, } from './hostFlows';
50
50
  import { importModelFile } from './assetLibrary/importModelFile';
51
51
  import { resolveControlSpec } from './poseMode/controlSpec';
52
52
  import { getUiConfig } from './uiConfig';
@@ -554,7 +554,7 @@ export function captureAnchorSeed(mainCam) {
554
554
  * UI 装配可配见 ./uiConfig:停靠框 portal 容器 / z-index 基准 / 语言
555
555
  * (宿主已包 I18nProvider 时语言以宿主为准,ui.locale 仅自包时生效)。
556
556
  */
557
- export function CameraScene({ project, onFlows, onError }) {
557
+ export function CameraScene({ project, onFlows, onError, includeDemoModel = true, }) {
558
558
  const t = useT();
559
559
  const cameraTargetRef = useRef(null);
560
560
  const cameraObjRef = useRef(undefined);
@@ -795,7 +795,7 @@ export function CameraScene({ project, onFlows, onError }) {
795
795
  const s = getStudio();
796
796
  return s?._store?._saaz ?? s?._saaz ?? 'no saaz';
797
797
  };
798
- const { placing, pendingEntry, startPlacingFromLibrary, placeLibraryEntryAt, cancelPlacing, confirmPlacing, clearPending, } = usePlacementController(project, sheet);
798
+ const { placing, pendingEntry, startPlacingFromLibrary, placeLibraryEntryAt, placePrimitiveAt, cancelPlacing, confirmPlacing, clearPending, } = usePlacementController(project, sheet);
799
799
  const [gizmoMode, setGizmoMode] = useGizmoMode();
800
800
  // 正在摆姿势的 placementKey(无会话为 null):Esc/双击空白/播放自动退出都靠它
801
801
  const poseSessionKey = usePoseSessionKey();
@@ -822,6 +822,33 @@ export function CameraScene({ project, onFlows, onError }) {
822
822
  setModelDragging(false);
823
823
  });
824
824
  }, [startPlacingFromLibrary]);
825
+ useEffect(() => {
826
+ if (!modelDragging)
827
+ return;
828
+ const onDragOver = (ev) => {
829
+ if (isDropPointInsideCanvas(ev.clientX, ev.clientY))
830
+ ev.preventDefault();
831
+ };
832
+ const onDrop = (ev) => {
833
+ ev.preventDefault();
834
+ if (isDropPointInsideCanvas(ev.clientX, ev.clientY)) {
835
+ const point = dropPointFromClient(ev.clientX, ev.clientY);
836
+ if (point) {
837
+ confirmPlacing(point);
838
+ setModelDragging(false);
839
+ return;
840
+ }
841
+ }
842
+ cancelPlacing();
843
+ setModelDragging(false);
844
+ };
845
+ window.addEventListener('dragover', onDragOver);
846
+ window.addEventListener('drop', onDrop);
847
+ return () => {
848
+ window.removeEventListener('dragover', onDragOver);
849
+ window.removeEventListener('drop', onDrop);
850
+ };
851
+ }, [modelDragging, confirmPlacing, cancelPlacing]);
825
852
  // 右键已放置模型弹出的操作菜单:记录目标条目和光标位置
826
853
  const [objectMenu, setObjectMenu] = useState(null);
827
854
  // 菜单关闭回调:稳定的引用,避免 CanvasContextMenu 不必要的重渲染
@@ -1363,6 +1390,7 @@ export function CameraScene({ project, onFlows, onError }) {
1363
1390
  gizmoMode,
1364
1391
  selectedPathPoint,
1365
1392
  placeLibraryEntryAt,
1393
+ placePrimitiveAt,
1366
1394
  enterPathEdit,
1367
1395
  exitPathEditOnBlur,
1368
1396
  afterSceneObjectDeleted,
@@ -1373,6 +1401,7 @@ export function CameraScene({ project, onFlows, onError }) {
1373
1401
  // 模型:转发 placeLibraryEntryAt(Task 8 已返回 {key, persisted},
1374
1402
  // 与 UI 点击放置同一条落地管线)
1375
1403
  createModel: ({ entry, position }) => deps().placeLibraryEntryAt(entry, position),
1404
+ createPrimitive: ({ kind, position }) => deps().placePrimitiveAt(kind, position),
1376
1405
  // 相机:Task 15 决策——生产绑定不自动 setActiveCameraKey。
1377
1406
  // create/setActive 是 spec §9 的两条显式命令,Agent 调用
1378
1407
  // cameras.create 不得隐性改变会话态;自动激活是 UI 顶栏
@@ -1441,7 +1470,8 @@ export function CameraScene({ project, onFlows, onError }) {
1441
1470
  const [coverGone, setCoverGone] = useState(false);
1442
1471
  const [firstScreenGate] = useState(() => {
1443
1472
  const gate = createFirstScreenGate(() => setFirstScreenReady(true));
1444
- gate.expect(SCENE_MODEL_GATE_KEY);
1473
+ if (includeDemoModel)
1474
+ gate.expect(SCENE_MODEL_GATE_KEY);
1445
1475
  installFirstScreenGate(gate);
1446
1476
  return gate;
1447
1477
  });
@@ -1633,9 +1663,9 @@ export function CameraScene({ project, onFlows, onError }) {
1633
1663
  React.createElement(e.mesh, { ref: cameraTargetRef, theatreKey: "Camera / Target", objRef: targetObjRef, hideFromOutline: true, position: DIRECTOR_HOME_TARGET_POSITION, visible: "editor" },
1634
1664
  React.createElement("boxGeometry", { attach: "geometry" }),
1635
1665
  React.createElement("meshPhongMaterial", { attach: "material", color: "red" })),
1636
- React.createElement(Suspense, { fallback: null },
1666
+ includeDemoModel && (React.createElement(Suspense, { fallback: null },
1637
1667
  React.createElement(InitialLoadProbe, { gateKey: SCENE_MODEL_GATE_KEY },
1638
- React.createElement(Model, { url: sceneGLB, selectLocked: !!placing }))),
1668
+ React.createElement(Model, { url: sceneGLB, selectLocked: !!placing })))),
1639
1669
  placing && (React.createElement(Suspense, { fallback: null },
1640
1670
  React.createElement(PlacementRigErrorBoundary, { onCancel: () => {
1641
1671
  cancelPlacing();
@@ -1,8 +1,10 @@
1
1
  import type { IProject, ISheet, ISheetObject } from '@dreamerbird/core';
2
2
  import React from 'react';
3
- import type { Group, Object3D, AnimationClip } from 'three';
3
+ import { Group } from 'three';
4
+ import type { Object3D, AnimationClip } from 'three';
4
5
  import type { Library } from './assetLibrary/library';
5
6
  import type { ModelEntry } from './assetLibrary/types';
7
+ import type { PrimitiveKind } from './primitives';
6
8
  /**
7
9
  * FBX 模型放置:页面顶部按钮选文件进入放置模式,半透明 ghost 跟随光标
8
10
  * (落点取物体表面优先,y=0 地面兜底),左键确认、Esc/右键取消。
@@ -33,6 +35,8 @@ export type PlacementEntry = {
33
35
  assetId?: string;
34
36
  /** 库来源条目的 id;存在时优先从资产库加载 GLB */
35
37
  libraryEntryId?: string;
38
+ primitive?: PrimitiveKind;
39
+ loadAttempt?: number;
36
40
  position: {
37
41
  x: number;
38
42
  y: number;
@@ -159,6 +163,14 @@ export declare function usePlacementController(project: IProject, sheet: ISheet)
159
163
  key: string;
160
164
  persisted: Promise<void>;
161
165
  };
166
+ placePrimitiveAt: (kind: PrimitiveKind, point: {
167
+ x: number;
168
+ y: number;
169
+ z: number;
170
+ }) => {
171
+ key: string;
172
+ persisted: Promise<void>;
173
+ };
162
174
  clearPending: () => void;
163
175
  };
164
176
  /**
@@ -214,6 +226,7 @@ export declare function loadLibraryModel(entryId: string, lib?: Library): Promis
214
226
  group: Group;
215
227
  animations: AnimationClip[];
216
228
  }>;
229
+ export declare function createFailedModelPlaceholder(key: string): Group;
217
230
  /** gizmo 的操作模式(标签文案在 menuModel 里经 t() 取);select = 只点选不挂手柄 */
218
231
  export type GizmoMode = 'select' | 'translate' | 'rotate' | 'scale';
219
232
  /**
@@ -232,6 +245,7 @@ export declare function useGizmoMode(): [GizmoMode, (mode: GizmoMode) => void];
232
245
  * 空壳在大纲里,刷新后消失——和撤销放置的已知行为一样。FBX 文件本体
233
246
  * 留在 IndexedDB。
234
247
  */
248
+ export declare function retryPlacement(sheet: ISheet, key: string, replacementEntryId?: string): boolean;
235
249
  export declare function deletePlacement(sheet: ISheet, key: string): void;
236
250
  /**
237
251
  * 选中对象的操作手柄:studio 选中状态里出现登记过的对象时,
@@ -1 +1 @@
1
- {"version":3,"file":"PlacementManager.d.ts","sourceRoot":"","sources":["../src/PlacementManager.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PlacementManager.d.ts","sourceRoot":"","sources":["../src/PlacementManager.tsx"],"names":[],"mappings":"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"}
@@ -9,7 +9,7 @@ import getStudio from '@dreamerbird/studio/getStudio';
9
9
  import { TransformControls, useFBX } from '@react-three/drei';
10
10
  import { useFrame, useThree } from '@react-three/fiber';
11
11
  import React, { Suspense, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
12
- import { AnimationMixer, Box3, BoxGeometry, Mesh, MeshBasicMaterial, Raycaster, Vector3, } from 'three';
12
+ import { AnimationMixer, Box3, BoxGeometry, Group, Mesh, MeshBasicMaterial, Raycaster, Vector3, } from 'three';
13
13
  import { SkeletonUtils } from 'three-stdlib';
14
14
  import { registerBoneAnchors, unregisterBoneAnchors } from './boneAnchors';
15
15
  import { notifyTargetRegistryChange, sheetObjectExists } from './aimTargets';
@@ -35,6 +35,9 @@ import { collectLibPoseIdsForProps, getPoseTrackId, getTrackIdForProp, } from '.
35
35
  import { gesturePropConfigShape, resolveGestureBones } from './gestureProps';
36
36
  import { computeLegacyPoseMigration } from './poseMode/poseMigration';
37
37
  import { parsePoseValue } from './poseMode/poseValue';
38
+ import { createPrimitive } from './primitives';
39
+ import { cloneModelMaterials, collectMaterialSlots, createMaterialOverridesConfig, } from './materials/modelMaterials';
40
+ import { useModelMaterials } from './materials/useModelMaterials';
38
41
  import { formatSceneObjectId } from './agent/objectIds';
39
42
  import { registerSceneSheetObject, unregisterSceneSheetObject, } from './agent/runtime/objectRuntime';
40
43
  import { createPlacementWaiter, rejectPlacement, resolvePlacementPersisted, } from './agent/runtime/placementLifecycle';
@@ -466,6 +469,13 @@ export function usePlacementController(project, sheet) {
466
469
  });
467
470
  return { key, persisted };
468
471
  }, [sheet]);
472
+ const placePrimitiveAt = useCallback((kind, point) => {
473
+ const key = uniquePlacedModelKey(sheet, kind);
474
+ const persisted = createPlacementWaiter(key);
475
+ persisted.catch(() => { });
476
+ setPendingEntry({ key, primitive: kind, position: point, pending: true });
477
+ return { key, persisted };
478
+ }, [sheet]);
469
479
  const clearPending = useCallback(() => setPendingEntry(null), []);
470
480
  return {
471
481
  placing,
@@ -475,6 +485,7 @@ export function usePlacementController(project, sheet) {
475
485
  cancelPlacing,
476
486
  confirmPlacing,
477
487
  placeLibraryEntryAt,
488
+ placePrimitiveAt,
478
489
  clearPending,
479
490
  };
480
491
  }
@@ -620,8 +631,9 @@ function PlacementRigCore({ model, onConfirm, onCancel, confirmOnPointerUp, }) {
620
631
  if (!confirmOnPointerUp)
621
632
  return;
622
633
  const el = gl.domElement;
634
+ let nativeDragOverCanvas = false;
623
635
  const onUp = (ev) => {
624
- if (ev.button !== 0)
636
+ if (ev.button !== 0 || nativeDragOverCanvas)
625
637
  return;
626
638
  // 画布铺满全窗口、垫在面板之下:松手在面板/工具栏等 DOM 上时 target 不是画布,
627
639
  // 必须取消(spec:松手在面板区域 = 静默取消)。提示条 pointerEvents:none 不挡
@@ -636,9 +648,45 @@ function PlacementRigCore({ model, onConfirm, onCancel, confirmOnPointerUp, }) {
636
648
  }
637
649
  onConfirm({ x: p.x, y: p.y, z: p.z });
638
650
  };
651
+ const onDragOver = (ev) => {
652
+ ev.preventDefault();
653
+ nativeDragOverCanvas = true;
654
+ pendingMoveRef.current = { x: ev.clientX, y: ev.clientY };
655
+ invalidate();
656
+ };
657
+ const onDragLeave = () => {
658
+ nativeDragOverCanvas = false;
659
+ };
660
+ const onDrop = (ev) => {
661
+ ev.preventDefault();
662
+ ev.stopPropagation();
663
+ nativeDragOverCanvas = false;
664
+ const p = computePoint(ev.clientX, ev.clientY);
665
+ if (p.distanceTo(camera.position) > 300) {
666
+ onCancel();
667
+ return;
668
+ }
669
+ onConfirm({ x: p.x, y: p.y, z: p.z });
670
+ };
639
671
  window.addEventListener('pointerup', onUp);
640
- return () => window.removeEventListener('pointerup', onUp);
641
- }, [confirmOnPointerUp, gl, camera, computePoint, onConfirm, onCancel]);
672
+ el.addEventListener('dragover', onDragOver);
673
+ el.addEventListener('dragleave', onDragLeave);
674
+ el.addEventListener('drop', onDrop);
675
+ return () => {
676
+ window.removeEventListener('pointerup', onUp);
677
+ el.removeEventListener('dragover', onDragOver);
678
+ el.removeEventListener('dragleave', onDragLeave);
679
+ el.removeEventListener('drop', onDrop);
680
+ };
681
+ }, [
682
+ confirmOnPointerUp,
683
+ gl,
684
+ camera,
685
+ computePoint,
686
+ invalidate,
687
+ onConfirm,
688
+ onCancel,
689
+ ]);
642
690
  return (
643
691
  // 首次 pointermove 之前不显示,避免在原地闪一下
644
692
  React.createElement("group", { ref: ghostRef, scale: scale, visible: false },
@@ -685,15 +733,26 @@ export function PlacedModels({ sheet, project, pendingEntry, onPersisted, select
685
733
  }, [ready, entriesKey]);
686
734
  if (!ready)
687
735
  return null;
688
- return (React.createElement(React.Fragment, null, entries.map((entry) => (React.createElement(Suspense, { key: entry.key, fallback: null },
736
+ return (React.createElement(React.Fragment, null, entries.map((entry) => (React.createElement(Suspense, { key: `${entry.key}:${entry.loadAttempt ?? 0}`, fallback: null },
689
737
  React.createElement(PlacedModelErrorBoundary, { entry: entry, project: project, sheet: sheet, onPersisted: onPersisted, selectLocked: selectLocked, onObjectMenu: onObjectMenu }))))));
690
738
  }
691
739
  function PlacedModel({ entry, project, sheet, onPersisted, selectLocked, onObjectMenu, }) {
740
+ if (entry.primitive) {
741
+ return (React.createElement(PrimitivePlacedModel, { entry: entry, sheet: sheet, onPersisted: onPersisted, selectLocked: selectLocked, onObjectMenu: onObjectMenu }));
742
+ }
692
743
  if (entry.libraryEntryId) {
693
744
  return (React.createElement(LibraryPlacedModel, { entry: entry, project: project, sheet: sheet, onPersisted: onPersisted, selectLocked: selectLocked, onObjectMenu: onObjectMenu }));
694
745
  }
695
746
  return (React.createElement(FBXPlacedModel, { entry: entry, project: project, sheet: sheet, onPersisted: onPersisted, selectLocked: selectLocked, onObjectMenu: onObjectMenu }));
696
747
  }
748
+ function PrimitivePlacedModel({ entry, sheet, onPersisted, selectLocked, onObjectMenu, }) {
749
+ const group = useMemo(() => {
750
+ const primitiveGroup = new Group();
751
+ primitiveGroup.add(createPrimitive(entry.primitive));
752
+ return primitiveGroup;
753
+ }, [entry.primitive]);
754
+ return (React.createElement(PlacedModelCore, { entry: entry, sheet: sheet, group: group, animations: [], sourceType: "primitive", onPersisted: onPersisted, selectLocked: selectLocked, onObjectMenu: onObjectMenu }));
755
+ }
697
756
  /** 旧本地 FBX 路径:通过 theatre assetStorage 取 URL,再用 useFBX 加载 */
698
757
  function FBXPlacedModel({ entry, project, sheet, onPersisted, selectLocked, onObjectMenu, }) {
699
758
  const url = useMemo(() => {
@@ -764,12 +823,19 @@ function LibraryPlacedModel({ entry, project, sheet, onPersisted, selectLocked,
764
823
  }
765
824
  /** 已加载 Group 之后的公共逻辑:克隆、归一化、动画 mixer、点选菜单、持久化 */
766
825
  function PlacedModelCore({ entry, sheet, group, animations, sourceType, onPersisted, selectLocked, onObjectMenu, }) {
767
- // 两条加载路径(库 GLB / 本地 FBX)都在这里汇合:挂载即「这个模型
826
+ // 三条来源路径(库 GLB / 本地 FBX / 基础几何体)都在这里汇合:挂载即「这个模型
768
827
  // 落定了」,上报首屏闸门(失败路径由 PlacedModelErrorBoundary 上报)
769
828
  useEffect(() => {
770
829
  getFirstScreenGate().settle(entry.key);
771
830
  // entry.key 挂载期内不变
772
831
  }, []);
832
+ const instance = useMemo(() => {
833
+ const cloned = SkeletonUtils.clone(group);
834
+ cloneModelMaterials(cloned);
835
+ return cloned;
836
+ }, [group]);
837
+ const materialSlots = useMemo(() => collectMaterialSlots(instance), [instance]);
838
+ const materialOverrides = useMemo(() => createMaterialOverridesConfig(materialSlots), [materialSlots]);
773
839
  const additionalProps = useMemo(() => {
774
840
  const modelEntryId = sourceType === 'library' ? entry.libraryEntryId : undefined;
775
841
  const props = {
@@ -787,12 +853,13 @@ function PlacedModelCore({ entry, sheet, group, animations, sourceType, onPersis
787
853
  label: () => translate('pg.props.poseOverride'),
788
854
  hidden: true,
789
855
  }),
856
+ materialOverrides,
790
857
  };
791
858
  if (sourceType === 'local' && entry.assetId) {
792
859
  props.source = fileConfigFor(entry.assetId);
793
860
  }
794
861
  return props;
795
- }, [sourceType, entry.assetId, entry.libraryEntryId]);
862
+ }, [sourceType, entry.assetId, entry.libraryEntryId, materialOverrides]);
796
863
  const { scale, lift } = useNormalizedModel(group);
797
864
  const objRef = useRef(undefined);
798
865
  const [sheetObject, setSheetObject] = useState(undefined);
@@ -819,6 +886,7 @@ function PlacedModelCore({ entry, sheet, group, animations, sourceType, onPersis
819
886
  // 登记为选中 gizmo 的附着目标:被选中时身上挂三轴移动箭头
820
887
  useSelectionGizmoTarget(objRef, groupRef);
821
888
  const invalidate = useThree((s) => s.invalidate);
889
+ useModelMaterials({ instance, sheetObject, slots: materialSlots, invalidate });
822
890
  // 主画面点选:和 App 里 Model 的 selectThingy 同款。放置模式下点击是
823
891
  // 确认落点,不选中、不拦截;点 gizmo 箭头穿透过来的误点也要吞掉。
824
892
  const selectSelf = (event) => {
@@ -866,10 +934,6 @@ function PlacedModelCore({ entry, sheet, group, animations, sourceType, onPersis
866
934
  event.stopPropagation();
867
935
  enterPoseSession(entry.key);
868
936
  };
869
- // 骨架动画:加载结果按 URL 缓存,同一文件放多个会共享同一份骨架,
870
- // 互相打架(多个 <primitive> 挂同一个 Object3D 也只有最后一个能显示)。
871
- // 所以每个实例克隆一份(SkinnedMesh 安全),配独立的 AnimationMixer。
872
- const instance = useMemo(() => SkeletonUtils.clone(group), [group]);
873
937
  const mixer = useMemo(() => new AnimationMixer(instance), [instance]);
874
938
  // 登记进 placedInstances 表:锚点父级绑定的 model: 解析用
875
939
  usePlacedInstance(entry.key, instance);
@@ -1065,7 +1129,7 @@ function PlacedModelCore({ entry, sheet, group, animations, sourceType, onPersis
1065
1129
  pendingUncachesRef.current = [];
1066
1130
  mixer.stopAllAction();
1067
1131
  mixer.uncacheRoot(instance);
1068
- disposeObjectTree(instance);
1132
+ disposeObjectTree(instance, { disposeTextures: false });
1069
1133
  };
1070
1134
  }, [mixer, instance]);
1071
1135
  // 只在 theatre 序列播放时驱动动画:编辑/摆姿势时模型保持静止。
@@ -1190,7 +1254,20 @@ function PlacedModelCore({ entry, sheet, group, animations, sourceType, onPersis
1190
1254
  React.createElement(PoseModeRig, { instance: instance, sheetObject: sheetObject, placementKey: entry.key, sheet: sheet }),
1191
1255
  React.createElement(PoseModeBar, { instance: instance })))));
1192
1256
  }
1193
- /** 本地缺资产(另一个客户端同步来的清单)或 FBX 解析失败时,跳过该模型而不是崩掉画布 */
1257
+ export function createFailedModelPlaceholder(key) {
1258
+ const group = new Group();
1259
+ group.name = `Failed/${key}`;
1260
+ const marker = new Mesh(new BoxGeometry(1, 1, 1), new MeshBasicMaterial({ color: 0xcc4444, wireframe: true }));
1261
+ marker.name = `Failed/${key}/Placeholder`;
1262
+ group.add(marker);
1263
+ return group;
1264
+ }
1265
+ function FailedPlacedModel({ entry }) {
1266
+ const group = useMemo(() => createFailedModelPlaceholder(entry.key), [entry.key]);
1267
+ useEffect(() => () => disposeObjectTree(group), [group]);
1268
+ return (React.createElement("group", { position: [entry.position.x, entry.position.y, entry.position.z] },
1269
+ React.createElement("primitive", { object: group })));
1270
+ }
1194
1271
  class PlacedModelErrorBoundary extends React.Component {
1195
1272
  constructor() {
1196
1273
  super(...arguments);
@@ -1208,7 +1285,11 @@ class PlacedModelErrorBoundary extends React.Component {
1208
1285
  rejectPlacement(this.props.entry.key, err);
1209
1286
  }
1210
1287
  render() {
1211
- return this.state.failed ? null : React.createElement(PlacedModel, { ...this.props });
1288
+ if (!this.state.failed)
1289
+ return React.createElement(PlacedModel, { ...this.props });
1290
+ if ('pending' in this.props.entry && this.props.entry.pending)
1291
+ return null;
1292
+ return React.createElement(FailedPlacedModel, { entry: this.props.entry });
1212
1293
  }
1213
1294
  }
1214
1295
  /**
@@ -1258,6 +1339,34 @@ export function useGizmoMode() {
1258
1339
  * 空壳在大纲里,刷新后消失——和撤销放置的已知行为一样。FBX 文件本体
1259
1340
  * 留在 IndexedDB。
1260
1341
  */
1342
+ export function retryPlacement(sheet, key, replacementEntryId) {
1343
+ const studio = getStudio();
1344
+ if (!studio)
1345
+ return false;
1346
+ const registry = getRegistry(sheet);
1347
+ const list = readRegistry(registry);
1348
+ const current = list.find((entry) => entry.key === key);
1349
+ if (!current)
1350
+ return false;
1351
+ const next = {
1352
+ key: current.key,
1353
+ position: current.position,
1354
+ loadAttempt: (current.loadAttempt ?? 0) + 1,
1355
+ ...(replacementEntryId === undefined
1356
+ ? current.libraryEntryId
1357
+ ? { libraryEntryId: current.libraryEntryId }
1358
+ : current.assetId
1359
+ ? { assetId: current.assetId }
1360
+ : current.primitive
1361
+ ? { primitive: current.primitive }
1362
+ : {}
1363
+ : { libraryEntryId: replacementEntryId }),
1364
+ };
1365
+ studio.transaction(({ set }) => {
1366
+ set(registry.props.list, JSON.stringify(list.map((entry) => (entry.key === key ? next : entry))));
1367
+ });
1368
+ return true;
1369
+ }
1261
1370
  export function deletePlacement(sheet, key) {
1262
1371
  const studio = getStudio();
1263
1372
  if (!studio)
@@ -4,6 +4,8 @@ import type { AgentRuntime, AgentSceneRuntimeHandlers } from './runtime';
4
4
  import type { SceneApi, ObjectsApi } from './commands/scene';
5
5
  import type { SelectionApi } from './commands/selection';
6
6
  import type { ModelsApi } from './commands/models';
7
+ import type { PrimitivesApi } from './commands/primitives';
8
+ import type { MaterialsApi } from './commands/materials';
7
9
  import type { AssetsApi } from './commands/assets';
8
10
  import type { PosesApi, PosesSessionApi } from './commands/poses';
9
11
  import type { AnimationsApi } from './commands/animations';
@@ -28,10 +30,13 @@ export type CameraStudioApi = {
28
30
  readonly ready: Promise<void>;
29
31
  /** 当前会话的命令清单与元数据(spec 8.1);未激活 API_NOT_READY,已拆解 API_DISPOSED */
30
32
  describe(): RegistryDescription;
33
+ subscribe(listener: () => void): () => void;
31
34
  readonly scene: SceneApi;
32
35
  readonly selection: SelectionApi;
33
36
  readonly objects: ObjectsApi;
34
37
  readonly models: ModelsApi;
38
+ readonly primitives: PrimitivesApi;
39
+ readonly materials: MaterialsApi;
35
40
  readonly assets: AssetsApi;
36
41
  readonly poses: PosesApi & {
37
42
  readonly session: PosesSessionApi;
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/agent/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/agent/api.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAC,oBAAoB,EAAC,MAAM,YAAY,CAAA;AAC/C,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,YAAY,CAAA;AACnD,OAAO,KAAK,EAAC,YAAY,EAAE,yBAAyB,EAAC,MAAM,WAAW,CAAA;AAItE,OAAO,KAAK,EAAC,QAAQ,EAAE,UAAU,EAAC,MAAM,kBAAkB,CAAA;AAC1D,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,sBAAsB,CAAA;AACtD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,uBAAuB,CAAA;AACxD,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,sBAAsB,CAAA;AACtD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,EAAC,QAAQ,EAAE,eAAe,EAAC,MAAM,kBAAkB,CAAA;AAC/D,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,uBAAuB,CAAA;AACxD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,EAAC,QAAQ,EAAE,eAAe,EAAC,MAAM,kBAAkB,CAAA;AAC/D,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,qBAAqB,CAAA;AACpD,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,sBAAsB,CAAA;AACtD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,eAAe,CAAA;AACxC,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAA;AAE5C,0CAA0C;AAC1C,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7B,iEAAiE;IACjE,QAAQ,IAAI,mBAAmB,CAAA;IAC/B,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;IAC3C,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAA;IAChC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;IAC5B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;IAC1B,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAA;IAClC,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAA;IAChC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;IAC1B,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG;QAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;KAAC,CAAA;IAC9D,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAA;IAClC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;IAC5B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;IAC5B,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG;QAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;KAAC,CAAA;IAC9D,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAA;IAC9B,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAA;IAChC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;IAC5B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAA;IAClB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;IAC5B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;IAC5B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CACvB,CAAA;AAUD,KAAK,eAAe,GAAG,CAAC,OAAO,EAAE,YAAY,KAAK,oBAAoB,CAAA;AAQtE,sDAAsD;AACtD,MAAM,MAAM,sBAAsB,GAAG;IACnC,aAAa,CAAC,EAAE,eAAe,CAAA;CAChC,CAAA;AAED,sBAAsB;AACtB,MAAM,MAAM,8BAA8B,GAAG;IAC3C,0DAA0D;IAC1D,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAA;IAC7B,6CAA6C;IAC7C,QAAQ,CACN,OAAO,EAAE,YAAY,EACrB,OAAO,CAAC,EAAE,8BAA8B,GACvC,IAAI,CAAA;IACP,yDAAyD;IACzD,OAAO,IAAI,IAAI,CAAA;IACf;;;;OAIG;IACH,iBAAiB,CACf,QAAQ,EAAE,OAAO,CAAC,yBAAyB,CAAC,GAC3C,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAA;IAC3B,mCAAmC;IACnC,cAAc,IAAI,YAAY,GAAG,SAAS,CAAA;IAC1C,mCAAmC;IACnC,eAAe,IAAI,oBAAoB,GAAG,SAAS,CAAA;CACpD,CAAA;AAuBD,wBAAgB,qBAAqB,CACnC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,yBAAyB,CAqT3B;AAKD,iDAAiD;AACjD,wBAAgB,kBAAkB,IAAI,eAAe,CAEpD;AAED,+CAA+C;AAC/C,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,YAAY,EACrB,OAAO,CAAC,EAAE,8BAA8B,GACvC,IAAI,CAEN;AAED,sCAAsC;AACtC,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAED,kEAAkE;AAClE,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,OAAO,CAAC,yBAAyB,CAAC,GAC3C,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAE1B;AAED,mDAAmD;AACnD,wBAAgB,qBAAqB,IAAI,YAAY,GAAG,SAAS,CAEhE;AAED,0DAA0D;AAC1D,wBAAgB,sBAAsB,IAAI,oBAAoB,GAAG,SAAS,CAEzE"}
package/dist/agent/api.js CHANGED
@@ -23,6 +23,7 @@
23
23
  import { AgentApiError } from './errors';
24
24
  import { AgentCommandRegistry } from './registry';
25
25
  import { isGenerationSupersededError } from './runtime';
26
+ import { subscribeSceneSheetObjects } from './runtime/objectRuntime';
26
27
  import { registerAllAgentCommands } from './registerCommands';
27
28
  const defaultRegistryFactory = (runtime) => {
28
29
  const registry = new AgentCommandRegistry();
@@ -120,6 +121,20 @@ export function createCameraStudioApi(options) {
120
121
  }
121
122
  throw new AgentApiError('API_NOT_READY', 'Camera Studio API 尚未激活(场景未挂载)');
122
123
  },
124
+ subscribe(listener) {
125
+ const captured = session;
126
+ if (!captured)
127
+ return () => { };
128
+ const studio = captured.runtime.getStudio();
129
+ const offSelection = studio?.onSelectionChange(() => listener()) ?? (() => { });
130
+ const offHistoric = captured.runtime.subscribeHistoric(listener);
131
+ const offSceneObjects = subscribeSceneSheetObjects(listener);
132
+ return () => {
133
+ offSelection();
134
+ offHistoric();
135
+ offSceneObjects();
136
+ };
137
+ },
123
138
  scene: {
124
139
  getSnapshot: () => invoke('scene.getSnapshot', undefined),
125
140
  },
@@ -136,11 +151,21 @@ export function createCameraStudioApi(options) {
136
151
  },
137
152
  models: {
138
153
  create: (args) => invoke('models.create', args),
154
+ retry: (args) => invoke('models.retry', args),
155
+ replace: (args) => invoke('models.replace', args),
156
+ },
157
+ primitives: {
158
+ create: (args) => invoke('primitives.create', args),
159
+ },
160
+ materials: {
161
+ list: (args) => invoke('materials.list', args),
162
+ update: (args) => invoke('materials.update', args),
139
163
  },
140
164
  assets: {
141
165
  list: (args) => invoke('assets.list', args),
142
166
  get: (args) => invoke('assets.get', args),
143
167
  importModel: (args) => invoke('assets.importModel', args),
168
+ importModels: (args) => invoke('assets.importModels', args),
144
169
  rename: (args) => invoke('assets.rename', args),
145
170
  delete: (args) => invoke('assets.delete', args),
146
171
  },