@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
@@ -238,7 +238,16 @@ export class Library {
238
238
  await this.enqueue(async () => {
239
239
  const writable = this.requireWritable();
240
240
  const blobId = await writable.putBlob(data);
241
- await writable.putEntry(makeEntry(blobId));
241
+ try {
242
+ await writable.putEntry(makeEntry(blobId));
243
+ }
244
+ catch (error) {
245
+ const referenced = await this.referencedBlobIdsForRollback().catch(() => undefined);
246
+ if (referenced && !referenced.has(blobId)) {
247
+ await writable.deleteBlob(blobId).catch(() => { });
248
+ }
249
+ throw error;
250
+ }
242
251
  this.emit();
243
252
  });
244
253
  }
@@ -265,6 +274,18 @@ export class Library {
265
274
  }
266
275
  return ids;
267
276
  }
277
+ async referencedBlobIdsForRollback() {
278
+ const catalogs = await Promise.all(this.sources.map((source) => source.listEntries()));
279
+ const ids = new Set();
280
+ for (const entry of catalogs.flat()) {
281
+ if ('blobId' in entry)
282
+ ids.add(entry.blobId);
283
+ if ('thumbnailId' in entry && entry.thumbnailId) {
284
+ ids.add(entry.thumbnailId);
285
+ }
286
+ }
287
+ return ids;
288
+ }
268
289
  /** 删条目并清理它的 blob;blob 被其他条目共享时保留 */
269
290
  async deleteEntryDeep(id) {
270
291
  await this.enqueue(async () => {
@@ -400,6 +400,82 @@ describe('骨架族别名并集读(终审 M-4)', () => {
400
400
  });
401
401
  });
402
402
  describe('blob 生命周期', () => {
403
+ test('putBlobWithEntry rolls back the upload when entry creation fails', async () => {
404
+ const backend = memoryBackend();
405
+ const failure = new Error('entry write failed');
406
+ backend.putEntry = async () => {
407
+ throw failure;
408
+ };
409
+ backend.deleteBlob = jest.fn(async () => { });
410
+ const lib = new Library({ sources: [backend] });
411
+ await expect(lib.putBlobWithEntry(new Blob(['model']), model)).rejects.toBe(failure);
412
+ expect(backend.deleteBlob).toHaveBeenCalledWith('blob-x');
413
+ });
414
+ test('putBlobWithEntry preserves a blob referenced by an existing entry after a later failure', async () => {
415
+ const backend = new IndexedDBBackend();
416
+ const lib = new Library({ sources: [backend] });
417
+ const bytes = new Blob(['shared-model-bytes']);
418
+ let sharedBlobId = '';
419
+ await lib.putBlobWithEntry(bytes, (blobId) => {
420
+ sharedBlobId = blobId;
421
+ return { ...model('shared-original'), blobId, contentHash: blobId };
422
+ });
423
+ const failure = new Error('second entry write failed');
424
+ backend.putEntry = async () => {
425
+ throw failure;
426
+ };
427
+ await expect(lib.putBlobWithEntry(bytes, (blobId) => ({
428
+ ...model('shared-second'),
429
+ blobId,
430
+ contentHash: blobId,
431
+ }))).rejects.toBe(failure);
432
+ expect(await lib.listBlobIds()).toContain(sharedBlobId);
433
+ expect(await lib.getEntry('shared-original')).toMatchObject({
434
+ blobId: sharedBlobId,
435
+ });
436
+ });
437
+ test('putBlobWithEntry preserves shared bytes and the original error when any source cannot be enumerated', async () => {
438
+ const backend = new IndexedDBBackend();
439
+ const sourceFailure = new Error('catalog source unavailable');
440
+ let sourceEntries = [];
441
+ let sourceUnavailable = false;
442
+ const unavailableSource = {
443
+ id: 'unavailable-source',
444
+ listEntries: async () => {
445
+ if (sourceUnavailable)
446
+ throw sourceFailure;
447
+ return sourceEntries;
448
+ },
449
+ getEntry: async (id) => sourceEntries.find((entry) => entry.id === id),
450
+ getBlobUrl: async () => {
451
+ throw sourceFailure;
452
+ },
453
+ };
454
+ const lib = new Library({ sources: [backend, unavailableSource] });
455
+ const bytes = new Blob(['shared-partial-catalog-bytes']);
456
+ let sharedBlobId = '';
457
+ await lib.putBlobWithEntry(bytes, (blobId) => {
458
+ sharedBlobId = blobId;
459
+ return { ...model('shared-partial-original'), blobId, contentHash: blobId };
460
+ });
461
+ sourceEntries = [(await backend.getEntry('shared-partial-original'))];
462
+ await backend.deleteEntry('shared-partial-original');
463
+ sourceUnavailable = true;
464
+ const failure = new Error('partial catalog entry write failed');
465
+ backend.putEntry = async () => {
466
+ throw failure;
467
+ };
468
+ await expect(lib.putBlobWithEntry(bytes, (blobId) => ({
469
+ ...model('shared-partial-second'),
470
+ blobId,
471
+ contentHash: blobId,
472
+ }))).rejects.toBe(failure);
473
+ await expect(backend.getBlobUrl(sharedBlobId)).resolves.toBe('blob:mock-url');
474
+ expect(await unavailableSource.getEntry('shared-partial-original')).toMatchObject({
475
+ blobId: sharedBlobId,
476
+ });
477
+ await backend.deleteBlob(sharedBlobId);
478
+ });
403
479
  test('deleteEntryDeep: 缩略图被两个模型共享时,删一个不删 blob', async () => {
404
480
  const lib = new Library({ sources: [new IndexedDBBackend()] });
405
481
  const thumbId = await lib.putBlob(new Blob(['thumb']));
@@ -7,7 +7,7 @@ export interface BootCtx {
7
7
  library: Library;
8
8
  unregisterEditors: () => void;
9
9
  /** 节流通道手动 flush:dispose 时调用,尾部变更不丢 */
10
- flushState: () => void;
10
+ flushState: () => Promise<void>;
11
11
  /**
12
12
  * 状态通道入口:生产由 project 历史指针订阅喂入,测试可直接调。
13
13
  * 尾部节流(缺省 1000ms)后转给 config.state.onStateChange。
@@ -34,4 +34,5 @@ export declare function isBootedWithDifferentConfig(config: CameraStudioConfig):
34
34
  export declare function getBootConfig(): CameraStudioConfig | undefined;
35
35
  export declare function initCameraStudio(config: CameraStudioConfig): Promise<BootCtx>;
36
36
  export declare function disposeCameraStudio(ctx?: BootCtx): Promise<void>;
37
+ export declare function resetCameraStudio(): Promise<void>;
37
38
  //# sourceMappingURL=bootstrap.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":"AAuBA,OAAO,qBAAqB,CAAA;AAO5B,OAAO,KAAK,EAAC,gBAAgB,EAAE,kBAAkB,EAAC,MAAM,UAAU,CAAA;AAKlE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,wBAAwB,CAAA;AAmBnD,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,aAAa,CAAA;AAOhD,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,kBAAkB,CAAA;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,iBAAiB,EAAE,MAAM,IAAI,CAAA;IAC7B,sCAAsC;IACtC,UAAU,EAAE,MAAM,IAAI,CAAA;IACtB;;;OAGG;IACH,iBAAiB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IAC7C,UAAU,EAAE,gBAAgB,CAAA;IAC5B,uDAAuD;IACvD,GAAG,EAAE,eAAe,CAAA;CACrB;AAYD;;;GAGG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,CAEpD;AACD,wBAAgB,2BAA2B,IAAI,MAAM,CAEpD;AAqBD,+DAA+D;AAC/D,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,kBAAkB,GACzB,gBAAgB,CAMlB;AA0CD;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAIT;AAED,0DAA0D;AAC1D,wBAAgB,aAAa,IAAI,kBAAkB,GAAG,SAAS,CAE9D;AA6QD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,CA4B7E;AAED,wBAAsB,mBAAmB,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAMtE"}
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":"AAwBA,OAAO,qBAAqB,CAAA;AAS5B,OAAO,KAAK,EAAC,gBAAgB,EAAE,kBAAkB,EAAC,MAAM,UAAU,CAAA;AAKlE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,wBAAwB,CAAA;AAqBnD,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,aAAa,CAAA;AAOhD,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,kBAAkB,CAAA;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,iBAAiB,EAAE,MAAM,IAAI,CAAA;IAC7B,sCAAsC;IACtC,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/B;;;OAGG;IACH,iBAAiB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IAC7C,UAAU,EAAE,gBAAgB,CAAA;IAC5B,uDAAuD;IACvD,GAAG,EAAE,eAAe,CAAA;CACrB;AAaD;;;GAGG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,CAEpD;AACD,wBAAgB,2BAA2B,IAAI,MAAM,CAEpD;AAuBD,+DAA+D;AAC/D,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,kBAAkB,GACzB,gBAAgB,CASlB;AA0CD;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAIT;AAED,0DAA0D;AAC1D,wBAAgB,aAAa,IAAI,kBAAkB,GAAG,SAAS,CAE9D;AAoRD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,CA6B7E;AAED,wBAAsB,mBAAmB,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAMtE;AAED,wBAAgB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CA4CjD"}
package/dist/bootstrap.js CHANGED
@@ -5,7 +5,8 @@
5
5
  *
6
6
  * 生命周期分层(R14):
7
7
  * - boot 级(一次性,initPromise 保留):Library 单例、IDB 连接、词典、
8
- * theatre.init、project 解析、节流机械。重挂幂等复用,dispose 不拆。
8
+ * theatre.init、project 解析、节流机械。重挂幂等复用,dispose 不拆;
9
+ * 显式场景切换可在全部消费者卸载后经 resetCameraStudio 清空重 boot。
9
10
  * - 会话级(每次挂载 acquire,dispose 拆解):3 个自定义属性编辑器注册、
10
11
  * state 通道订阅、studio.ui 显隐。picker 注册表与宿主句柄由各自模块
11
12
  * 自管(CameraScene 组件挂载时接线),这里不碰。
@@ -18,6 +19,8 @@ import theatre, { getProject, getStudio, getStudioSync, onChange, } from '@dream
18
19
  import '@dreamerbird/studio';
19
20
  import { initState } from '@dreamerbird/core/initState';
20
21
  import { privateAPI } from '@dreamerbird/core/privateAPIs';
22
+ import projectsSingleton from '@dreamerbird/core/projects/projectsSingleton';
23
+ import getStudioInternal from '@dreamerbird/studio/getStudio';
21
24
  import { registerCustomPropEditor, unregisterCustomPropEditor, } from '@dreamerbird/studio/propEditors/customPropEditors';
22
25
  import { cameraErrorFromLibrary, cameraErrorFromUnknown } from './errors';
23
26
  import { registerCameraMessages } from './i18n';
@@ -28,9 +31,11 @@ import { StaticCatalogSource } from './assetLibrary/staticCatalogSource';
28
31
  import { isWritableSource } from './assetLibrary/source';
29
32
  import { cleanupLegacySeeds } from './assetLibrary/legacySeedCleanup';
30
33
  import { setUiConfig } from './uiConfig';
34
+ import { mountStudioRootWhenReady } from './studioRoot';
31
35
  import PosePropEditor from './poseMode/PosePropEditor';
32
36
  import { GesturePropEditorLeft, GesturePropEditorRight, } from './gesturePropsEditor';
33
37
  import { createAgentRuntime } from './agent/runtime';
38
+ import { clearSceneSheetObjects } from './agent/runtime/objectRuntime';
34
39
  import { activateCameraStudioApi, disposeCameraStudioApi, getActiveAgentRegistry, getCameraStudioApi, } from './agent/api';
35
40
  import { createAgentBridgeClient } from './agent/bridgeClient';
36
41
  /** 内置 IDB 缺省库名(与现状一字不差,硬约束:老用户浏览器里的库零迁移) */
@@ -40,6 +45,7 @@ let initPromise;
40
45
  let bootConfig;
41
46
  /** 漂移告警只发一次(同页多次重挂不同 config 不刷屏) */
42
47
  let warnedConfigDrift = false;
48
+ let resetPromise;
43
49
  /** 会话拆解函数;undefined = 当前无活跃会话(acquire 幂等守卫) */
44
50
  let sessionTeardown;
45
51
  /** 消费者计数由 hook 管(acquire/release 成对);dispose 据此做末位守卫 */
@@ -65,7 +71,12 @@ function resolveProject(config) {
65
71
  }
66
72
  const name = config.project ?? 'Space';
67
73
  const initialState = config.state?.initialState;
68
- return getProject(name, initialState === undefined ? {} : { state: initialState });
74
+ return getProject(name, {
75
+ ...(initialState === undefined ? {} : { state: initialState }),
76
+ ...(config.ui?.projectName === undefined
77
+ ? {}
78
+ : { name: config.ui.projectName }),
79
+ });
69
80
  }
70
81
  /** sceneProps 同步解析(hook 首帧就要返回;getProject 渲染期调用安全,App 既有先例) */
71
82
  export function resolveSceneProps(config) {
@@ -73,6 +84,9 @@ export function resolveSceneProps(config) {
73
84
  project: resolveProject(config),
74
85
  onFlows: config.flows?.onFlows,
75
86
  onError: config.onError,
87
+ ...(config.scene?.includeDemoModel === undefined
88
+ ? {}
89
+ : { includeDemoModel: config.scene.includeDemoModel }),
76
90
  };
77
91
  }
78
92
  /** 参与漂移比对的顶层配置键(flows 回调引用每次渲染都新,不比) */
@@ -185,6 +199,13 @@ async function boot(config) {
185
199
  if (config.ui?.hideLeftStrip) {
186
200
  withStudioUi((ui) => ui.setLeftStripHidden(true));
187
201
  }
202
+ if (config.ui?.panels) {
203
+ const panels = config.ui.panels;
204
+ withStudioUi((ui) => ui.setPanelVisibility(panels));
205
+ }
206
+ withStudioUi(() => {
207
+ void mountStudioRootWhenReady(config.ui?.portalContainer);
208
+ });
188
209
  // 1. 数据源:可写源(若有) + 内置目录,聚合进 Library 单例
189
210
  const { sources, idbName } = resolveSources(config);
190
211
  const catalog = new StaticCatalogSource({
@@ -238,7 +259,7 @@ async function boot(config) {
238
259
  let pendingContent;
239
260
  let hasPending = false;
240
261
  let timer;
241
- const flushState = () => {
262
+ const flushState = async () => {
242
263
  if (timer !== undefined) {
243
264
  clearTimeout(timer);
244
265
  timer = undefined;
@@ -248,7 +269,7 @@ async function boot(config) {
248
269
  hasPending = false;
249
270
  const content = pendingContent;
250
271
  pendingContent = undefined;
251
- config.state?.onStateChange?.(content);
272
+ await config.state?.onStateChange?.(content);
252
273
  };
253
274
  const notifyStateChange = (content) => {
254
275
  if (!config.state?.onStateChange)
@@ -277,7 +298,7 @@ async function boot(config) {
277
298
  }
278
299
  /** studio.ui 显隐操作:studio 未挂载(宿主以 studio:false init 等)时静默降级 */
279
300
  function withStudioUi(fn) {
280
- Promise.resolve()
301
+ return Promise.resolve()
281
302
  .then(() => getStudio())
282
303
  .then(async (studio) => {
283
304
  // 必须等 studio 初始化收尾(持久化/同步状态恢复落库)再读写显隐:
@@ -352,11 +373,13 @@ function acquireSession(ctx) {
352
373
  ctx.unregisterEditors();
353
374
  unsubState?.();
354
375
  // 先断订阅再 flush:尾部变更带给宿主,不丢
355
- ctx.flushState();
356
- withStudioUi((ui) => ui.hide());
376
+ await ctx.flushState();
377
+ await withStudioUi((ui) => ui.hide());
357
378
  };
358
379
  }
359
380
  export function initCameraStudio(config) {
381
+ if (resetPromise)
382
+ return resetPromise.then(() => initCameraStudio(config));
360
383
  if (!initPromise) {
361
384
  bootConfig = config;
362
385
  const p = boot(config);
@@ -392,3 +415,42 @@ export async function disposeCameraStudio(ctx) {
392
415
  return;
393
416
  await sessionTeardown?.();
394
417
  }
418
+ export function resetCameraStudio() {
419
+ if (resetPromise)
420
+ return resetPromise;
421
+ const previousInit = initPromise;
422
+ resetPromise = (async () => {
423
+ if (activeConsumers > 0) {
424
+ throw new Error('resetCameraStudio requires all camera-studio consumers to be unmounted');
425
+ }
426
+ const previousCtx = previousInit
427
+ ? await previousInit.catch(() => undefined)
428
+ : undefined;
429
+ if (activeConsumers > 0) {
430
+ throw new Error('resetCameraStudio requires all camera-studio consumers to be unmounted');
431
+ }
432
+ await sessionTeardown?.();
433
+ clearSceneSheetObjects();
434
+ if (previousCtx) {
435
+ const projectId = previousCtx.sceneProps.project.address.projectId;
436
+ projectsSingleton.remove(projectId);
437
+ const studio = getStudioInternal();
438
+ if (studio) {
439
+ studio.transaction(({ stateEditors }) => {
440
+ stateEditors.deleteProject({ projectId });
441
+ }, false);
442
+ studio.ephemeralAtom.reduceByPointer((p) => p.coreByProject, (projects) => {
443
+ const next = { ...projects };
444
+ delete next[projectId];
445
+ return next;
446
+ });
447
+ }
448
+ }
449
+ initPromise = undefined;
450
+ bootConfig = undefined;
451
+ warnedConfigDrift = false;
452
+ })().finally(() => {
453
+ resetPromise = undefined;
454
+ });
455
+ return resetPromise;
456
+ }
@@ -31,11 +31,13 @@ const initSpy = jest.fn(async (_opts) => { });
31
31
  const fakeSheet = { fakeSheet: true };
32
32
  const getProjectSpy = jest.fn((_name, _opts) => ({
33
33
  fake: true,
34
+ address: { projectId: _name },
34
35
  sheet: jest.fn(() => fakeSheet),
35
36
  }));
36
37
  // studio.ui 替身:hide/restore 翻转 isHidden(与真 UI 行为一致;
37
38
  // bootstrap 仅在 isHidden 时才 restore)
38
39
  const setLeftStripHiddenSpy = jest.fn();
40
+ const setPanelVisibilitySpy = jest.fn();
39
41
  const uiBox = {
40
42
  isHidden: false,
41
43
  hide: jest.fn(() => {
@@ -45,6 +47,7 @@ const uiBox = {
45
47
  uiBox.isHidden = false;
46
48
  }),
47
49
  setLeftStripHidden: setLeftStripHiddenSpy,
50
+ setPanelVisibility: setPanelVisibilitySpy,
48
51
  };
49
52
  const hideSpy = uiBox.hide;
50
53
  const restoreSpy = uiBox.restore;
@@ -103,6 +106,11 @@ initSpy.mockImplementation(async (opts) => {
103
106
  jest.doMock('@dreamerbird/studio', () => ({
104
107
  __esModule: true,
105
108
  }));
109
+ jest.doMock('@dreamerbird/studio/UI/UINonSSRBits', () => ({
110
+ __esModule: true,
111
+ default: class {
112
+ },
113
+ }));
106
114
  jest.doMock('@dreamerbird/core', () => ({
107
115
  __esModule: true,
108
116
  default: { init: initSpy },
@@ -158,6 +166,7 @@ beforeEach(async () => {
158
166
  uiBox.isHidden = false;
159
167
  initializedBox.promise = Promise.resolve();
160
168
  setLeftStripHiddenSpy.mockClear();
169
+ setPanelVisibilitySpy.mockClear();
161
170
  getStudioSyncSpy.mockClear();
162
171
  activateApiSpy.mockClear();
163
172
  disposeApiSpy.mockClear();
@@ -645,3 +654,105 @@ test('14. ui.hideLeftStrip → boot 经 studio.ui.setLeftStripHidden(true) 应
645
654
  expect(setLeftStripHiddenSpy).toHaveBeenCalledWith(true);
646
655
  await h.unmount();
647
656
  });
657
+ test('flushState emits the pending throttled state exactly once', async () => {
658
+ let resolveState;
659
+ const onStateChange = jest.fn(() => new Promise((resolve) => {
660
+ resolveState = resolve;
661
+ }));
662
+ const h = hookHost({ state: { onStateChange, throttleMs: 60000 } });
663
+ await h.mount();
664
+ const historicCallback = onChangeSpy.mock.calls[1][1];
665
+ historicCallback({ rev: 1 });
666
+ let flushed = false;
667
+ const firstFlush = h.result.current.flushState().then(() => {
668
+ flushed = true;
669
+ });
670
+ await Promise.resolve();
671
+ expect(onStateChange).toHaveBeenCalledTimes(1);
672
+ expect(onStateChange).toHaveBeenCalledWith({ rev: 1 });
673
+ expect(flushed).toBe(false);
674
+ resolveState();
675
+ await firstFlush;
676
+ await h.result.current.flushState();
677
+ expect(onStateChange).toHaveBeenCalledTimes(1);
678
+ await h.unmount();
679
+ });
680
+ test('ui.panels hides only the requested panel without changing timeline visibility', async () => {
681
+ const h = hookHost({ ui: { panels: { outline: false, details: true } } });
682
+ await h.mount();
683
+ await flush();
684
+ expect(setPanelVisibilitySpy).toHaveBeenCalledWith({
685
+ outline: false,
686
+ details: true,
687
+ });
688
+ expect(hideSpy).not.toHaveBeenCalled();
689
+ expect(restoreSpy).not.toHaveBeenCalled();
690
+ const [{ default: UI }, { Atom, val }] = await Promise.all([
691
+ import('@dreamerbird/studio/UI/UI'),
692
+ import('@dreamerbird/dataverse'),
693
+ ]);
694
+ const studio = {
695
+ ephemeralAtom: new Atom({}),
696
+ atomP: { ahistoric: { visibilityState: 'everythingIsVisible' } },
697
+ };
698
+ UI.prototype.setPanelVisibility.call({ studio }, {
699
+ outline: false,
700
+ details: true,
701
+ });
702
+ expect(val(studio.ephemeralAtom.pointer.hiddenPanels)).toEqual({
703
+ outline: true,
704
+ details: false,
705
+ });
706
+ expect(studio.atomP.ahistoric.visibilityState).toBe('everythingIsVisible');
707
+ await h.unmount();
708
+ });
709
+ test('resetCameraStudio clears retained project/state config across A→B→A remounts', async () => {
710
+ const stateA = { objects: { a: { position: [1, 0, 0] } } };
711
+ const stateB = { objects: { b: { position: [2, 0, 0] } } };
712
+ const stateA2 = { objects: { a2: { position: [3, 0, 0] } } };
713
+ const onA = jest.fn();
714
+ const onB = jest.fn();
715
+ const onA2 = jest.fn();
716
+ const a = hookHost({
717
+ project: 'SceneA',
718
+ storage: false,
719
+ state: { initialState: stateA, onStateChange: onA },
720
+ });
721
+ await a.mount();
722
+ const projectA = a.result.current?.sceneProps.project;
723
+ expect(projectA).toBeDefined();
724
+ await a.unmount();
725
+ await bootstrap.resetCameraStudio();
726
+ const b = hookHost({
727
+ project: 'SceneB',
728
+ storage: false,
729
+ state: { initialState: stateB, onStateChange: onB },
730
+ });
731
+ await b.mount();
732
+ expect(b.result.current?.sceneProps.project).not.toBe(projectA);
733
+ const projectB = b.result.current?.sceneProps.project;
734
+ const stateCallbackB = onChangeSpy.mock.calls.at(-1)?.[1];
735
+ stateCallbackB({ scene: 'B' });
736
+ await b.result.current.flushState();
737
+ expect(onB).toHaveBeenCalledWith({ scene: 'B' });
738
+ expect(onA).not.toHaveBeenCalled();
739
+ await b.unmount();
740
+ await bootstrap.resetCameraStudio();
741
+ const a2 = hookHost({
742
+ project: 'SceneA',
743
+ storage: false,
744
+ state: { initialState: stateA2, onStateChange: onA2 },
745
+ });
746
+ await a2.mount();
747
+ expect(a2.result.current?.sceneProps.project).not.toBe(projectA);
748
+ expect(a2.result.current?.sceneProps.project).not.toBe(projectB);
749
+ const stateCallbackA2 = onChangeSpy.mock.calls.at(-1)?.[1];
750
+ stateCallbackA2({ scene: 'A2' });
751
+ await a2.result.current.flushState();
752
+ expect(onA2).toHaveBeenCalledWith({ scene: 'A2' });
753
+ expect(onB).toHaveBeenCalledTimes(1);
754
+ await a2.unmount();
755
+ expect(getProjectSpy).toHaveBeenCalledWith('SceneA', { state: stateA });
756
+ expect(getProjectSpy).toHaveBeenCalledWith('SceneB', { state: stateB });
757
+ expect(getProjectSpy).toHaveBeenCalledWith('SceneA', { state: stateA2 });
758
+ });
package/dist/config.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * CameraFlows 类型取自 ./hostFlows(定义所在);简报草样写 './App',
5
5
  * 但 App.tsx 只默认导出组件、不转出口该类型,从定义处引入才编译得过。
6
6
  */
7
- import type { IProject } from '@dreamerbird/core';
7
+ import type { IProject, StudioPanelVisibility } from '@dreamerbird/core';
8
8
  import type { WritableLibrarySource } from './assetLibrary/source';
9
9
  import type { CameraStudioErrorHandler } from './errors';
10
10
  import type { CameraFlows } from './hostFlows';
@@ -60,12 +60,19 @@ export interface CameraStudioConfig {
60
60
  sync?: {
61
61
  serverUrl?: string;
62
62
  } | false;
63
+ scene?: {
64
+ /** 是否渲染内置 Thingy 演示模型;缺省 true */
65
+ includeDemoModel?: boolean;
66
+ };
63
67
  ui?: {
64
68
  portalContainer?: HTMLElement;
65
69
  zIndexBase?: number;
66
70
  locale?: string;
67
71
  /** 隐藏 studio 左上角带 logo 的整条 LeftStrip(应用 logo + 工作区按钮) */
68
72
  hideLeftStrip?: boolean;
73
+ panels?: StudioPanelVisibility;
74
+ /** Scene Tree 顶部项目节点的显示名;不改变持久化 projectId */
75
+ projectName?: string;
69
76
  };
70
77
  flows?: {
71
78
  onFlows?: (flows: CameraFlows) => void;
@@ -78,6 +85,7 @@ export type CameraSceneProps = {
78
85
  project: IProject;
79
86
  onFlows?: (flows: CameraFlows) => void;
80
87
  onError?: CameraStudioErrorHandler;
88
+ includeDemoModel?: boolean;
81
89
  };
82
90
  export interface CameraStudioHandle {
83
91
  ready: boolean;
@@ -88,5 +96,6 @@ export interface CameraStudioHandle {
88
96
  * 同一对象);`api.ready` 在 project+studio+Scene Runtime 就位后兑现
89
97
  */
90
98
  api: CameraStudioApi;
99
+ flushState(): Promise<void>;
91
100
  }
92
101
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,mBAAmB,CAAA;AAC/C,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,uBAAuB,CAAA;AAChE,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,UAAU,CAAA;AACtD,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,aAAa,CAAA;AAEhD;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAA;IACX;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,kDAAkD;AAClD,MAAM,MAAM,uBAAuB,GAAG;IACpC;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,8BAA8B;IAC9B,MAAM,CAAC,EAAE,6BAA6B,CAAA;CACvC,CAAA;AAED,MAAM,WAAW,kBAAkB;IACjC,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;IAC3B,kCAAkC;IAClC,KAAK,CAAC,EAAE;QACN,YAAY,CAAC,EAAE,OAAO,CAAA;QACtB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;QAC1C,iDAAiD;QACjD,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;IACD,8CAA8C;IAC9C,OAAO,CAAC,EAAE,wBAAwB,CAAA;IAClC;4DACwD;IACxD,OAAO,CAAC,EAAE,qBAAqB,GAAG;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAC,GAAG,KAAK,CAAA;IAC9D,0BAA0B;IAC1B,MAAM,CAAC,EAAE;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAC,CAAA;IAC3B,uBAAuB;IACvB,IAAI,CAAC,EAAE;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAC,GAAG,KAAK,CAAA;IACnC,EAAE,CAAC,EAAE;QACH,eAAe,CAAC,EAAE,WAAW,CAAA;QAC7B,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,yDAAyD;QACzD,aAAa,CAAC,EAAE,OAAO,CAAA;KACxB,CAAA;IACD,KAAK,CAAC,EAAE;QAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAA;KAAC,CAAA;IAChD,uCAAuC;IACvC,KAAK,CAAC,EAAE,uBAAuB,CAAA;CAChC;AAED,iDAAiD;AACjD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,QAAQ,CAAA;IACjB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAA;IACtC,OAAO,CAAC,EAAE,wBAAwB,CAAA;CACnC,CAAA;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,OAAO,CAAA;IACd,KAAK,EAAE,KAAK,GAAG,SAAS,CAAA;IACxB,UAAU,EAAE,gBAAgB,CAAA;IAC5B;;;OAGG;IACH,GAAG,EAAE,eAAe,CAAA;CACrB"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAC,QAAQ,EAAE,qBAAqB,EAAC,MAAM,mBAAmB,CAAA;AACtE,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,uBAAuB,CAAA;AAChE,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,UAAU,CAAA;AACtD,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,aAAa,CAAA;AAEhD;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAA;IACX;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,kDAAkD;AAClD,MAAM,MAAM,uBAAuB,GAAG;IACpC;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,8BAA8B;IAC9B,MAAM,CAAC,EAAE,6BAA6B,CAAA;CACvC,CAAA;AAED,MAAM,WAAW,kBAAkB;IACjC,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;IAC3B,kCAAkC;IAClC,KAAK,CAAC,EAAE;QACN,YAAY,CAAC,EAAE,OAAO,CAAA;QACtB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;QAC1C,iDAAiD;QACjD,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;IACD,8CAA8C;IAC9C,OAAO,CAAC,EAAE,wBAAwB,CAAA;IAClC;4DACwD;IACxD,OAAO,CAAC,EAAE,qBAAqB,GAAG;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAC,GAAG,KAAK,CAAA;IAC9D,0BAA0B;IAC1B,MAAM,CAAC,EAAE;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAC,CAAA;IAC3B,uBAAuB;IACvB,IAAI,CAAC,EAAE;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAC,GAAG,KAAK,CAAA;IACnC,KAAK,CAAC,EAAE;QACN,iCAAiC;QACjC,gBAAgB,CAAC,EAAE,OAAO,CAAA;KAC3B,CAAA;IACD,EAAE,CAAC,EAAE;QACH,eAAe,CAAC,EAAE,WAAW,CAAA;QAC7B,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,yDAAyD;QACzD,aAAa,CAAC,EAAE,OAAO,CAAA;QACvB,MAAM,CAAC,EAAE,qBAAqB,CAAA;QAC9B,6CAA6C;QAC7C,WAAW,CAAC,EAAE,MAAM,CAAA;KACrB,CAAA;IACD,KAAK,CAAC,EAAE;QAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAA;KAAC,CAAA;IAChD,uCAAuC;IACvC,KAAK,CAAC,EAAE,uBAAuB,CAAA;CAChC;AAED,iDAAiD;AACjD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,QAAQ,CAAA;IACjB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAA;IACtC,OAAO,CAAC,EAAE,wBAAwB,CAAA;IAClC,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B,CAAA;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,OAAO,CAAA;IACd,KAAK,EAAE,KAAK,GAAG,SAAS,CAAA;IACxB,UAAU,EAAE,gBAAgB,CAAA;IAC5B;;;OAGG;IACH,GAAG,EAAE,eAAe,CAAA;IACpB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAC5B"}
@@ -32,6 +32,7 @@ export type DropPointContext = {
32
32
  camera: Camera;
33
33
  };
34
34
  export declare function setDropPointContext(ctx: DropPointContext | null): void;
35
+ export declare function isDropPointInsideCanvas(clientX: number, clientY: number): boolean;
35
36
  export declare function dropPointFromClient(clientX: number, clientY: number): Vec3 | null;
36
37
  /**
37
38
  * App 用既有函数注入组装 CameraFlows;纯转发,可单测。
@@ -1 +1 @@
1
- {"version":3,"file":"hostFlows.d.ts","sourceRoot":"","sources":["../src/hostFlows.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hostFlows.d.ts","sourceRoot":"","sources":["../src/hostFlows.ts"],"names":[],"mappings":"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"}
package/dist/hostFlows.js CHANGED
@@ -46,6 +46,15 @@ let dropCtx = null;
46
46
  export function setDropPointContext(ctx) {
47
47
  dropCtx = ctx;
48
48
  }
49
+ export function isDropPointInsideCanvas(clientX, clientY) {
50
+ if (!dropCtx)
51
+ return false;
52
+ const rect = dropCtx.gl.domElement.getBoundingClientRect();
53
+ return (clientX >= rect.left &&
54
+ clientX <= rect.right &&
55
+ clientY >= rect.top &&
56
+ clientY <= rect.bottom);
57
+ }
49
58
  export function dropPointFromClient(clientX, clientY) {
50
59
  if (!dropCtx)
51
60
  return null;
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ export type { CameraStudioConfig, CameraStudioHandle, CameraSceneProps, CameraSt
6
6
  export type { CameraFlows, Vec3 } from './hostFlows';
7
7
  export type { PathPreset } from './pathPresets';
8
8
  export type { CameraStudioError, CameraStudioErrorHandler, CameraStudioErrorSource, } from './errors';
9
- export { initCameraStudio, disposeCameraStudio } from './bootstrap';
9
+ export { initCameraStudio, disposeCameraStudio, resetCameraStudio, } from './bootstrap';
10
10
  export type { BootCtx } from './bootstrap';
11
11
  export type { CameraStudioApi } from './agent/api';
12
12
  export { AgentApiError, AGENT_API_ERROR_CODES } from './agent/errors';
@@ -16,6 +16,10 @@ export type { SceneObjectId, SceneObjectKind, JobSnapshot, JobState, AgentErrorD
16
16
  export type { SceneApi, ObjectsApi, SceneSnapshot, SceneObjectSummary, } from './agent/commands/scene';
17
17
  export type { SelectionApi } from './agent/commands/selection';
18
18
  export type { ModelsApi } from './agent/commands/models';
19
+ export type { PrimitivesApi } from './agent/commands/primitives';
20
+ export type { PrimitiveKind } from './primitives';
21
+ export type { MaterialsApi } from './agent/commands/materials';
22
+ export type { MaterialSlot, MaterialValues } from './materials/types';
19
23
  export type { AssetsApi } from './agent/commands/assets';
20
24
  export type { PosesApi, PosesSessionApi } from './agent/commands/poses';
21
25
  export type { AnimationsApi, AnimationStatusDto, } from './agent/commands/animations';
@@ -35,8 +39,13 @@ export type { GizmoMode } from './PlacementManager';
35
39
  export type { PoseBones } from './poseMode/poseOverride';
36
40
  export type { GestureSide } from './gestureProps';
37
41
  export type { PoseFrameMode } from './poseMode/poseFrame';
42
+ export { BUILTIN_POSE_RIG, BUILTIN_POSE_SOURCES, listBuiltinPoses, getBuiltinPose, applyPose, capturePose, captureBindPose, } from './poses';
43
+ export type { BuiltinPoseSourceId } from './poses';
38
44
  export type { LibrarySource, LibrarySourceCapabilities, WritableLibrarySource, LibraryErrorCode, } from './assetLibrary/source';
39
45
  export { LibraryError, isWritableSource } from './assetLibrary/source';
40
46
  export type { RigId, RigAlias, EntryKind, ModelEntry, PoseEntry, AnimationEntry, LibraryEntry, } from './assetLibrary/types';
41
47
  export { IndexedDBBackend } from './assetLibrary/indexedDBBackend';
48
+ export { importModelFiles } from './assetLibrary/importModelFiles';
49
+ export { registerModelPicker, unregisterModelPicker } from './pickerRegistry';
50
+ export type { ModelPickerProps } from './pickerRegistry';
42
51
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -5,7 +5,12 @@ export { CameraScene } from './CameraScene';
5
5
  export { CAMERA_STUDIO_VERSION } from './version';
6
6
  export { useCameraStudio } from './useCameraStudio';
7
7
  // 测试与高级宿主可用:绕过 hook 直接管 init/dispose 生命周期
8
- export { initCameraStudio, disposeCameraStudio } from './bootstrap';
8
+ export { initCameraStudio, disposeCameraStudio, resetCameraStudio, } from './bootstrap';
9
9
  export { AgentApiError, AGENT_API_ERROR_CODES } from './agent/errors';
10
+ // 内置静态姿势库:引用本包的项目可直接取姿势数据并应用到自己的骨架,
11
+ // 不必先启动编辑器。轻量消费可走 `@dreamerbird/camera-studio/poses` 子路径
12
+ export { BUILTIN_POSE_RIG, BUILTIN_POSE_SOURCES, listBuiltinPoses, getBuiltinPose, applyPose, capturePose, captureBindPose, } from './poses';
10
13
  export { LibraryError, isWritableSource } from './assetLibrary/source';
11
14
  export { IndexedDBBackend } from './assetLibrary/indexedDBBackend';
15
+ export { importModelFiles } from './assetLibrary/importModelFiles';
16
+ export { registerModelPicker, unregisterModelPicker } from './pickerRegistry';
@@ -0,0 +1,19 @@
1
+ import { type Texture, type Object3D } from 'three';
2
+ import type { MaterialSlot, MaterialValues } from './types';
3
+ type MaterialOverrides = Record<string, Partial<MaterialValues>>;
4
+ export declare function cloneModelMaterials(root: Object3D): void;
5
+ export declare function collectMaterialSlots(root: Object3D): MaterialSlot[];
6
+ export declare function applyMaterialScalars(root: Object3D, slots: MaterialSlot[], overrides: MaterialOverrides): void;
7
+ export declare function createMaterialOverridesConfig(slots: MaterialSlot[]): any;
8
+ type TextureControllerOptions = {
9
+ getBlobUrl(blobId: string): Promise<string>;
10
+ loadTexture(url: string): Promise<Texture>;
11
+ onError?(error: unknown, slotId: string, property: string): void;
12
+ invalidate(): void;
13
+ };
14
+ export declare function createMaterialTextureController(options: TextureControllerOptions): {
15
+ update(root: Object3D, slots: MaterialSlot[], overrides: MaterialOverrides): Promise<void>;
16
+ dispose(): void;
17
+ };
18
+ export {};
19
+ //# sourceMappingURL=modelMaterials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modelMaterials.d.ts","sourceRoot":"","sources":["../../src/materials/modelMaterials.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,OAAO,EAEZ,KAAK,QAAQ,EACd,MAAM,OAAO,CAAA;AACd,OAAO,KAAK,EAAC,YAAY,EAAE,cAAc,EAAC,MAAM,SAAS,CAAA;AAWzD,KAAK,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAA;AAyDhE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAYxD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,GAAG,YAAY,EAAE,CAuBnE;AAqBD,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,YAAY,EAAE,EACrB,SAAS,EAAE,iBAAiB,GAC3B,IAAI,CA+BN;AAiBD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,YAAY,EAAE,OAkBlE;AAED,KAAK,wBAAwB,GAAG;IAC9B,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAC3C,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC1C,OAAO,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IAChE,UAAU,IAAI,IAAI,CAAA;CACnB,CAAA;AAED,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,wBAAwB;iBAyDvB,QAAQ,SACP,YAAY,EAAE,aACV,iBAAiB,GAC3B,OAAO,CAAC,IAAI,CAAC;eA4BL,IAAI;EAWlB"}