@dreamerbird/camera-studio 0.1.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 (139) hide show
  1. package/LICENSE +866 -0
  2. package/assets/models/Y Bot.glb +0 -0
  3. package/dist/CameraScene.d.ts +1 -1
  4. package/dist/CameraScene.d.ts.map +1 -1
  5. package/dist/CameraScene.js +100 -9
  6. package/dist/PlacementManager.d.ts +15 -1
  7. package/dist/PlacementManager.d.ts.map +1 -1
  8. package/dist/PlacementManager.js +151 -15
  9. package/dist/agent/api.d.ts +5 -0
  10. package/dist/agent/api.d.ts.map +1 -1
  11. package/dist/agent/api.js +25 -0
  12. package/dist/agent/api.test.js +75 -1
  13. package/dist/agent/commands/assets.d.ts +5 -0
  14. package/dist/agent/commands/assets.d.ts.map +1 -1
  15. package/dist/agent/commands/assets.js +93 -21
  16. package/dist/agent/commands/assets.test.js +53 -0
  17. package/dist/agent/commands/materials.d.ts +18 -0
  18. package/dist/agent/commands/materials.d.ts.map +1 -0
  19. package/dist/agent/commands/materials.js +192 -0
  20. package/dist/agent/commands/materials.test.d.ts +2 -0
  21. package/dist/agent/commands/materials.test.d.ts.map +1 -0
  22. package/dist/agent/commands/materials.test.js +294 -0
  23. package/dist/agent/commands/modelRecovery.test.d.ts +2 -0
  24. package/dist/agent/commands/modelRecovery.test.d.ts.map +1 -0
  25. package/dist/agent/commands/modelRecovery.test.js +122 -0
  26. package/dist/agent/commands/models.d.ts +13 -0
  27. package/dist/agent/commands/models.d.ts.map +1 -1
  28. package/dist/agent/commands/models.js +98 -1
  29. package/dist/agent/commands/primitives.d.ts +27 -0
  30. package/dist/agent/commands/primitives.d.ts.map +1 -0
  31. package/dist/agent/commands/primitives.js +117 -0
  32. package/dist/agent/commands/primitives.test.d.ts +2 -0
  33. package/dist/agent/commands/primitives.test.d.ts.map +1 -0
  34. package/dist/agent/commands/primitives.test.js +135 -0
  35. package/dist/agent/expectedCommands.d.ts +1 -1
  36. package/dist/agent/expectedCommands.d.ts.map +1 -1
  37. package/dist/agent/expectedCommands.js +6 -0
  38. package/dist/agent/propAccess.d.ts +2 -0
  39. package/dist/agent/propAccess.d.ts.map +1 -1
  40. package/dist/agent/propAccess.js +21 -0
  41. package/dist/agent/registerCommands.d.ts.map +1 -1
  42. package/dist/agent/registerCommands.js +5 -1
  43. package/dist/agent/runtime/objectRuntime.d.ts +2 -0
  44. package/dist/agent/runtime/objectRuntime.d.ts.map +1 -1
  45. package/dist/agent/runtime/objectRuntime.js +15 -1
  46. package/dist/agent/runtime.d.ts +1 -0
  47. package/dist/agent/runtime.d.ts.map +1 -1
  48. package/dist/agent/runtime.js +2 -0
  49. package/dist/assetLibrary/dispose.d.ts +4 -2
  50. package/dist/assetLibrary/dispose.d.ts.map +1 -1
  51. package/dist/assetLibrary/dispose.js +7 -5
  52. package/dist/assetLibrary/exportGLB.d.ts +25 -0
  53. package/dist/assetLibrary/exportGLB.d.ts.map +1 -1
  54. package/dist/assetLibrary/exportGLB.js +43 -1
  55. package/dist/assetLibrary/exportGLB.test.js +56 -2
  56. package/dist/assetLibrary/gltfLoader.d.ts +2 -1
  57. package/dist/assetLibrary/gltfLoader.d.ts.map +1 -1
  58. package/dist/assetLibrary/gltfLoader.js +2 -2
  59. package/dist/assetLibrary/gltfResourceSet.d.ts +6 -0
  60. package/dist/assetLibrary/gltfResourceSet.d.ts.map +1 -0
  61. package/dist/assetLibrary/gltfResourceSet.js +27 -0
  62. package/dist/assetLibrary/gltfResourceSet.test.d.ts +2 -0
  63. package/dist/assetLibrary/gltfResourceSet.test.d.ts.map +1 -0
  64. package/dist/assetLibrary/gltfResourceSet.test.js +40 -0
  65. package/dist/assetLibrary/importModelFile.d.ts +5 -0
  66. package/dist/assetLibrary/importModelFile.d.ts.map +1 -1
  67. package/dist/assetLibrary/importModelFile.js +3 -16
  68. package/dist/assetLibrary/importModelFiles.d.ts +15 -0
  69. package/dist/assetLibrary/importModelFiles.d.ts.map +1 -0
  70. package/dist/assetLibrary/importModelFiles.js +58 -0
  71. package/dist/assetLibrary/importModelFiles.test.d.ts +2 -0
  72. package/dist/assetLibrary/importModelFiles.test.d.ts.map +1 -0
  73. package/dist/assetLibrary/importModelFiles.test.js +217 -0
  74. package/dist/assetLibrary/importPipeline.d.ts +15 -1
  75. package/dist/assetLibrary/importPipeline.d.ts.map +1 -1
  76. package/dist/assetLibrary/importPipeline.js +74 -38
  77. package/dist/assetLibrary/importPipeline.test.js +25 -0
  78. package/dist/assetLibrary/library.d.ts +1 -0
  79. package/dist/assetLibrary/library.d.ts.map +1 -1
  80. package/dist/assetLibrary/library.js +22 -1
  81. package/dist/assetLibrary/library.test.js +76 -0
  82. package/dist/assetLibrary/seedAssetsManifest.js +1 -1
  83. package/dist/bootstrap.d.ts +2 -1
  84. package/dist/bootstrap.d.ts.map +1 -1
  85. package/dist/bootstrap.js +69 -7
  86. package/dist/bootstrap.test.js +111 -0
  87. package/dist/config.d.ts +10 -1
  88. package/dist/config.d.ts.map +1 -1
  89. package/dist/firstScreenGate.d.ts +28 -0
  90. package/dist/firstScreenGate.d.ts.map +1 -0
  91. package/dist/firstScreenGate.js +67 -0
  92. package/dist/firstScreenGate.test.d.ts +2 -0
  93. package/dist/firstScreenGate.test.d.ts.map +1 -0
  94. package/dist/firstScreenGate.test.js +83 -0
  95. package/dist/hostFlows.d.ts +1 -0
  96. package/dist/hostFlows.d.ts.map +1 -1
  97. package/dist/hostFlows.js +9 -0
  98. package/dist/index.d.ts +10 -1
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +6 -1
  101. package/dist/materials/modelMaterials.d.ts +19 -0
  102. package/dist/materials/modelMaterials.d.ts.map +1 -0
  103. package/dist/materials/modelMaterials.js +253 -0
  104. package/dist/materials/modelMaterials.test.d.ts +2 -0
  105. package/dist/materials/modelMaterials.test.d.ts.map +1 -0
  106. package/dist/materials/modelMaterials.test.js +188 -0
  107. package/dist/materials/types.d.ts +20 -0
  108. package/dist/materials/types.d.ts.map +1 -0
  109. package/dist/materials/types.js +1 -0
  110. package/dist/materials/useModelMaterials.d.ts +10 -0
  111. package/dist/materials/useModelMaterials.d.ts.map +1 -0
  112. package/dist/materials/useModelMaterials.js +26 -0
  113. package/dist/materials/useModelMaterials.test.d.ts +2 -0
  114. package/dist/materials/useModelMaterials.test.d.ts.map +1 -0
  115. package/dist/materials/useModelMaterials.test.js +75 -0
  116. package/dist/poses.d.ts +38 -0
  117. package/dist/poses.d.ts.map +1 -0
  118. package/dist/poses.js +41 -0
  119. package/dist/poses.test.d.ts +2 -0
  120. package/dist/poses.test.d.ts.map +1 -0
  121. package/dist/poses.test.js +38 -0
  122. package/dist/primitives.d.ts +5 -0
  123. package/dist/primitives.d.ts.map +1 -0
  124. package/dist/primitives.js +15 -0
  125. package/dist/primitives.test.d.ts +2 -0
  126. package/dist/primitives.test.d.ts.map +1 -0
  127. package/dist/primitives.test.js +27 -0
  128. package/dist/reset.realStudio.test.d.ts +2 -0
  129. package/dist/reset.realStudio.test.d.ts.map +1 -0
  130. package/dist/reset.realStudio.test.js +60 -0
  131. package/dist/studioRoot.d.ts +4 -0
  132. package/dist/studioRoot.d.ts.map +1 -0
  133. package/dist/studioRoot.js +36 -0
  134. package/dist/studioRoot.test.d.ts +2 -0
  135. package/dist/studioRoot.test.d.ts.map +1 -0
  136. package/dist/studioRoot.test.js +62 -0
  137. package/dist/useCameraStudio.d.ts.map +1 -1
  138. package/dist/useCameraStudio.js +3 -2
  139. package/package.json +18 -10
@@ -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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * 首屏就绪闸门(2026-10-22):聚合「工程就绪 + 首批场景资源加载落定」,
3
+ * 就绪前 CameraScene 盖加载遮罩——此前顶栏/轴向控制器等同步部件首帧就画,
4
+ * 模型和面板走各自异步(Suspense fallback=null / 库加载)settled 才补,
5
+ * 开场观感参差。闸门只闸首屏:落定一次后,后续放置/加载不再触发遮盖。
6
+ *
7
+ * 模块级单值通路(与 getLibrary/poseSession 同风格):CameraScene 创建并
8
+ * 安装;PlacementManager 各层经 getFirstScreenGate() 上报,免层层传 prop;
9
+ * 未安装时返回 no-op(测试或宿主绕过 CameraScene 直用 PlacementManager 不炸)。
10
+ */
11
+ export interface FirstScreenGate {
12
+ /** 工程就绪(useProjectReady 变真时调;幂等) */
13
+ setProjectReady(): void;
14
+ /** 登记一个首屏要等的资源;已落定过的 key 不重复登记(清单重扫防回加) */
15
+ expect(key: string): void;
16
+ /** 上报一个资源落定(加载成功或失败都算;未登记的 key 忽略) */
17
+ settle(key: string): void;
18
+ /** 落定后 expect/settle 全是 no-op */
19
+ readonly fired: boolean;
20
+ }
21
+ export declare const FIRST_SCREEN_TIMEOUT_MS = 15000;
22
+ export declare function createFirstScreenGate(onReady: () => void, timeoutMs?: number, warn?: (msg: string) => void): FirstScreenGate;
23
+ /** CameraScene 装配期调用(必须在子树 effect 之前,见调用点注释) */
24
+ export declare function installFirstScreenGate(gate: FirstScreenGate): void;
25
+ export declare function getFirstScreenGate(): FirstScreenGate;
26
+ /** CameraScene 卸载/测试复位用 */
27
+ export declare function resetFirstScreenGate(): void;
28
+ //# sourceMappingURL=firstScreenGate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firstScreenGate.d.ts","sourceRoot":"","sources":["../src/firstScreenGate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,eAAe,IAAI,IAAI,CAAA;IACvB,2CAA2C;IAC3C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,sCAAsC;IACtC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,iCAAiC;IACjC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CACxB;AAED,eAAO,MAAM,uBAAuB,QAAQ,CAAA;AAE5C,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,IAAI,EACnB,SAAS,GAAE,MAAgC,EAC3C,IAAI,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAmB,GACzC,eAAe,CA8CjB;AAYD,gDAAgD;AAChD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAElE;AAED,wBAAgB,kBAAkB,IAAI,eAAe,CAEpD;AAED,2BAA2B;AAC3B,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C"}
@@ -0,0 +1,67 @@
1
+ export const FIRST_SCREEN_TIMEOUT_MS = 15000;
2
+ export function createFirstScreenGate(onReady, timeoutMs = FIRST_SCREEN_TIMEOUT_MS, warn = console.warn) {
3
+ const pending = new Set();
4
+ const settled = new Set();
5
+ let projectReady = false;
6
+ let fired = false;
7
+ // 兜底:某个资源悬挂(网络卡死等)不能让用户永远看遮罩,超时强制揭幕
8
+ const timer = setTimeout(() => {
9
+ warn(`[firstScreen] 首屏等待超过 ${timeoutMs}ms 强制揭幕(未落定:${[...pending].join(', ') || '无'};工程就绪:${projectReady})`);
10
+ fire();
11
+ }, timeoutMs);
12
+ // Node 的 Timeout 才有 unref(浏览器返回 number):防测试进程被计时器挂住
13
+ if (typeof timer === 'object' && typeof timer.unref === 'function') {
14
+ timer.unref();
15
+ }
16
+ function fire() {
17
+ if (fired)
18
+ return;
19
+ fired = true;
20
+ clearTimeout(timer);
21
+ onReady();
22
+ }
23
+ function check() {
24
+ if (projectReady && pending.size === 0)
25
+ fire();
26
+ }
27
+ return {
28
+ get fired() {
29
+ return fired;
30
+ },
31
+ setProjectReady() {
32
+ projectReady = true;
33
+ check();
34
+ },
35
+ expect(key) {
36
+ if (fired || settled.has(key))
37
+ return;
38
+ pending.add(key);
39
+ },
40
+ settle(key) {
41
+ if (fired || !pending.has(key))
42
+ return;
43
+ pending.delete(key);
44
+ settled.add(key);
45
+ check();
46
+ },
47
+ };
48
+ }
49
+ /** 未安装时的默认闸门:fired=true 的 no-op,上报全部吞掉 */
50
+ const noopGate = {
51
+ fired: true,
52
+ setProjectReady() { },
53
+ expect() { },
54
+ settle() { },
55
+ };
56
+ let current = noopGate;
57
+ /** CameraScene 装配期调用(必须在子树 effect 之前,见调用点注释) */
58
+ export function installFirstScreenGate(gate) {
59
+ current = gate;
60
+ }
61
+ export function getFirstScreenGate() {
62
+ return current;
63
+ }
64
+ /** CameraScene 卸载/测试复位用 */
65
+ export function resetFirstScreenGate() {
66
+ current = noopGate;
67
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=firstScreenGate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firstScreenGate.test.d.ts","sourceRoot":"","sources":["../src/firstScreenGate.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,83 @@
1
+ import { createFirstScreenGate } from './firstScreenGate';
2
+ describe('createFirstScreenGate', () => {
3
+ it('工程就绪且无可等资源 → 立即落定', () => {
4
+ const onReady = jest.fn();
5
+ const gate = createFirstScreenGate(onReady);
6
+ expect(onReady).not.toHaveBeenCalled();
7
+ gate.setProjectReady();
8
+ expect(onReady).toHaveBeenCalledTimes(1);
9
+ expect(gate.fired).toBe(true);
10
+ });
11
+ it('有待载资源:全部 settle 且工程就绪才落定(先载完后就绪也成立)', () => {
12
+ const onReady = jest.fn();
13
+ const gate = createFirstScreenGate(onReady);
14
+ gate.expect('a');
15
+ gate.expect('b');
16
+ gate.settle('a');
17
+ gate.settle('b');
18
+ expect(onReady).not.toHaveBeenCalled(); // 工程未就绪
19
+ gate.setProjectReady();
20
+ expect(onReady).toHaveBeenCalledTimes(1);
21
+ });
22
+ it('部分 settle 不落定', () => {
23
+ const onReady = jest.fn();
24
+ const gate = createFirstScreenGate(onReady);
25
+ gate.expect('a');
26
+ gate.expect('b');
27
+ gate.setProjectReady();
28
+ gate.settle('a');
29
+ expect(onReady).not.toHaveBeenCalled();
30
+ gate.settle('b');
31
+ expect(onReady).toHaveBeenCalledTimes(1);
32
+ });
33
+ it('未登记的 settle 被忽略,不影响计数', () => {
34
+ const onReady = jest.fn();
35
+ const gate = createFirstScreenGate(onReady);
36
+ gate.expect('a');
37
+ gate.settle('陌生人');
38
+ gate.setProjectReady();
39
+ expect(onReady).not.toHaveBeenCalled();
40
+ gate.settle('a');
41
+ expect(onReady).toHaveBeenCalledTimes(1);
42
+ });
43
+ it('已落定的 key 再 expect 不回加(放置清单重扫场景)', () => {
44
+ const onReady = jest.fn();
45
+ const gate = createFirstScreenGate(onReady);
46
+ gate.expect('a');
47
+ gate.setProjectReady();
48
+ gate.settle('a');
49
+ expect(onReady).toHaveBeenCalledTimes(1);
50
+ // 清单重扫又把 a 登记一遍 + 新条目 b —— 闸门已落定,全部忽略
51
+ gate.expect('a');
52
+ gate.expect('b');
53
+ expect(onReady).toHaveBeenCalledTimes(1);
54
+ });
55
+ it('落定只触发一次(setProjectReady/settle 重复调用幂等)', () => {
56
+ const onReady = jest.fn();
57
+ const gate = createFirstScreenGate(onReady);
58
+ gate.setProjectReady();
59
+ gate.setProjectReady();
60
+ gate.settle('从未登记');
61
+ expect(onReady).toHaveBeenCalledTimes(1);
62
+ });
63
+ it('超时强制揭幕并告警,之后不再重复触发', () => {
64
+ jest.useFakeTimers();
65
+ try {
66
+ const onReady = jest.fn();
67
+ const warn = jest.fn();
68
+ const gate = createFirstScreenGate(onReady, 5000, warn);
69
+ gate.expect('卡住的模型');
70
+ jest.advanceTimersByTime(5000);
71
+ expect(warn).toHaveBeenCalledTimes(1);
72
+ expect(warn.mock.calls[0][0]).toContain('卡住的模型');
73
+ expect(onReady).toHaveBeenCalledTimes(1);
74
+ // 超时后迟到的 settle 不再触发
75
+ gate.settle('卡住的模型');
76
+ jest.advanceTimersByTime(10000);
77
+ expect(onReady).toHaveBeenCalledTimes(1);
78
+ }
79
+ finally {
80
+ jest.useRealTimers();
81
+ }
82
+ });
83
+ });
@@ -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"}