@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.
- package/LICENSE +866 -0
- package/assets/models/Y Bot.glb +0 -0
- package/dist/CameraScene.d.ts +1 -1
- package/dist/CameraScene.d.ts.map +1 -1
- package/dist/CameraScene.js +100 -9
- package/dist/PlacementManager.d.ts +15 -1
- package/dist/PlacementManager.d.ts.map +1 -1
- package/dist/PlacementManager.js +151 -15
- package/dist/agent/api.d.ts +5 -0
- package/dist/agent/api.d.ts.map +1 -1
- package/dist/agent/api.js +25 -0
- package/dist/agent/api.test.js +75 -1
- package/dist/agent/commands/assets.d.ts +5 -0
- package/dist/agent/commands/assets.d.ts.map +1 -1
- package/dist/agent/commands/assets.js +93 -21
- package/dist/agent/commands/assets.test.js +53 -0
- package/dist/agent/commands/materials.d.ts +18 -0
- package/dist/agent/commands/materials.d.ts.map +1 -0
- package/dist/agent/commands/materials.js +192 -0
- package/dist/agent/commands/materials.test.d.ts +2 -0
- package/dist/agent/commands/materials.test.d.ts.map +1 -0
- package/dist/agent/commands/materials.test.js +294 -0
- package/dist/agent/commands/modelRecovery.test.d.ts +2 -0
- package/dist/agent/commands/modelRecovery.test.d.ts.map +1 -0
- package/dist/agent/commands/modelRecovery.test.js +122 -0
- package/dist/agent/commands/models.d.ts +13 -0
- package/dist/agent/commands/models.d.ts.map +1 -1
- package/dist/agent/commands/models.js +98 -1
- package/dist/agent/commands/primitives.d.ts +27 -0
- package/dist/agent/commands/primitives.d.ts.map +1 -0
- package/dist/agent/commands/primitives.js +117 -0
- package/dist/agent/commands/primitives.test.d.ts +2 -0
- package/dist/agent/commands/primitives.test.d.ts.map +1 -0
- package/dist/agent/commands/primitives.test.js +135 -0
- package/dist/agent/expectedCommands.d.ts +1 -1
- package/dist/agent/expectedCommands.d.ts.map +1 -1
- package/dist/agent/expectedCommands.js +6 -0
- package/dist/agent/propAccess.d.ts +2 -0
- package/dist/agent/propAccess.d.ts.map +1 -1
- package/dist/agent/propAccess.js +21 -0
- package/dist/agent/registerCommands.d.ts.map +1 -1
- package/dist/agent/registerCommands.js +5 -1
- package/dist/agent/runtime/objectRuntime.d.ts +2 -0
- package/dist/agent/runtime/objectRuntime.d.ts.map +1 -1
- package/dist/agent/runtime/objectRuntime.js +15 -1
- package/dist/agent/runtime.d.ts +1 -0
- package/dist/agent/runtime.d.ts.map +1 -1
- package/dist/agent/runtime.js +2 -0
- package/dist/assetLibrary/dispose.d.ts +4 -2
- package/dist/assetLibrary/dispose.d.ts.map +1 -1
- package/dist/assetLibrary/dispose.js +7 -5
- package/dist/assetLibrary/exportGLB.d.ts +25 -0
- package/dist/assetLibrary/exportGLB.d.ts.map +1 -1
- package/dist/assetLibrary/exportGLB.js +43 -1
- package/dist/assetLibrary/exportGLB.test.js +56 -2
- package/dist/assetLibrary/gltfLoader.d.ts +2 -1
- package/dist/assetLibrary/gltfLoader.d.ts.map +1 -1
- package/dist/assetLibrary/gltfLoader.js +2 -2
- package/dist/assetLibrary/gltfResourceSet.d.ts +6 -0
- package/dist/assetLibrary/gltfResourceSet.d.ts.map +1 -0
- package/dist/assetLibrary/gltfResourceSet.js +27 -0
- package/dist/assetLibrary/gltfResourceSet.test.d.ts +2 -0
- package/dist/assetLibrary/gltfResourceSet.test.d.ts.map +1 -0
- package/dist/assetLibrary/gltfResourceSet.test.js +40 -0
- package/dist/assetLibrary/importModelFile.d.ts +5 -0
- package/dist/assetLibrary/importModelFile.d.ts.map +1 -1
- package/dist/assetLibrary/importModelFile.js +3 -16
- package/dist/assetLibrary/importModelFiles.d.ts +15 -0
- package/dist/assetLibrary/importModelFiles.d.ts.map +1 -0
- package/dist/assetLibrary/importModelFiles.js +58 -0
- package/dist/assetLibrary/importModelFiles.test.d.ts +2 -0
- package/dist/assetLibrary/importModelFiles.test.d.ts.map +1 -0
- package/dist/assetLibrary/importModelFiles.test.js +217 -0
- package/dist/assetLibrary/importPipeline.d.ts +15 -1
- package/dist/assetLibrary/importPipeline.d.ts.map +1 -1
- package/dist/assetLibrary/importPipeline.js +74 -38
- package/dist/assetLibrary/importPipeline.test.js +25 -0
- package/dist/assetLibrary/library.d.ts +1 -0
- package/dist/assetLibrary/library.d.ts.map +1 -1
- package/dist/assetLibrary/library.js +22 -1
- package/dist/assetLibrary/library.test.js +76 -0
- package/dist/assetLibrary/seedAssetsManifest.js +1 -1
- package/dist/bootstrap.d.ts +2 -1
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +69 -7
- package/dist/bootstrap.test.js +111 -0
- package/dist/config.d.ts +10 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/firstScreenGate.d.ts +28 -0
- package/dist/firstScreenGate.d.ts.map +1 -0
- package/dist/firstScreenGate.js +67 -0
- package/dist/firstScreenGate.test.d.ts +2 -0
- package/dist/firstScreenGate.test.d.ts.map +1 -0
- package/dist/firstScreenGate.test.js +83 -0
- package/dist/hostFlows.d.ts +1 -0
- package/dist/hostFlows.d.ts.map +1 -1
- package/dist/hostFlows.js +9 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/materials/modelMaterials.d.ts +19 -0
- package/dist/materials/modelMaterials.d.ts.map +1 -0
- package/dist/materials/modelMaterials.js +253 -0
- package/dist/materials/modelMaterials.test.d.ts +2 -0
- package/dist/materials/modelMaterials.test.d.ts.map +1 -0
- package/dist/materials/modelMaterials.test.js +188 -0
- package/dist/materials/types.d.ts +20 -0
- package/dist/materials/types.d.ts.map +1 -0
- package/dist/materials/types.js +1 -0
- package/dist/materials/useModelMaterials.d.ts +10 -0
- package/dist/materials/useModelMaterials.d.ts.map +1 -0
- package/dist/materials/useModelMaterials.js +26 -0
- package/dist/materials/useModelMaterials.test.d.ts +2 -0
- package/dist/materials/useModelMaterials.test.d.ts.map +1 -0
- package/dist/materials/useModelMaterials.test.js +75 -0
- package/dist/poses.d.ts +38 -0
- package/dist/poses.d.ts.map +1 -0
- package/dist/poses.js +41 -0
- package/dist/poses.test.d.ts +2 -0
- package/dist/poses.test.d.ts.map +1 -0
- package/dist/poses.test.js +38 -0
- package/dist/primitives.d.ts +5 -0
- package/dist/primitives.d.ts.map +1 -0
- package/dist/primitives.js +15 -0
- package/dist/primitives.test.d.ts +2 -0
- package/dist/primitives.test.d.ts.map +1 -0
- package/dist/primitives.test.js +27 -0
- package/dist/reset.realStudio.test.d.ts +2 -0
- package/dist/reset.realStudio.test.d.ts.map +1 -0
- package/dist/reset.realStudio.test.js +60 -0
- package/dist/studioRoot.d.ts +4 -0
- package/dist/studioRoot.d.ts.map +1 -0
- package/dist/studioRoot.js +36 -0
- package/dist/studioRoot.test.d.ts +2 -0
- package/dist/studioRoot.test.d.ts.map +1 -0
- package/dist/studioRoot.test.js +62 -0
- package/dist/useCameraStudio.d.ts.map +1 -1
- package/dist/useCameraStudio.js +3 -2
- package/package.json +18 -10
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { AgentApiError } from '../errors';
|
|
2
|
+
import { formatSceneObjectId } from '../objectIds';
|
|
3
|
+
import { getSceneObjectSummary } from '../objectResolver';
|
|
4
|
+
import { requireFiniteNumber, requireObject, requireString, requireVec3, } from '../validation';
|
|
5
|
+
import { PRIMITIVE_KINDS } from '../../primitives';
|
|
6
|
+
const createInput = {
|
|
7
|
+
type: 'object',
|
|
8
|
+
properties: {
|
|
9
|
+
kind: {
|
|
10
|
+
type: 'string',
|
|
11
|
+
enum: [...PRIMITIVE_KINDS],
|
|
12
|
+
description: '米制基础几何体类型',
|
|
13
|
+
},
|
|
14
|
+
position: {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
x: { type: 'number' },
|
|
18
|
+
y: { type: 'number' },
|
|
19
|
+
z: { type: 'number' },
|
|
20
|
+
},
|
|
21
|
+
required: ['x', 'y', 'z'],
|
|
22
|
+
additionalProperties: false,
|
|
23
|
+
description: '创建位置(世界坐标)',
|
|
24
|
+
},
|
|
25
|
+
expectedRevision: {
|
|
26
|
+
type: 'number',
|
|
27
|
+
description: '乐观并发:读取场景时的 revision',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
required: ['kind', 'position'],
|
|
31
|
+
additionalProperties: false,
|
|
32
|
+
};
|
|
33
|
+
const createOutput = {
|
|
34
|
+
type: 'object',
|
|
35
|
+
properties: {
|
|
36
|
+
objectId: { type: 'string', description: '带类型场景对象 ID,model:<key>' },
|
|
37
|
+
revision: { type: 'number' },
|
|
38
|
+
},
|
|
39
|
+
required: ['objectId', 'revision'],
|
|
40
|
+
};
|
|
41
|
+
function validateCreate(value) {
|
|
42
|
+
const args = requireObject(value);
|
|
43
|
+
const kind = requireString(args, 'kind');
|
|
44
|
+
if (!PRIMITIVE_KINDS.includes(kind)) {
|
|
45
|
+
throw new AgentApiError('INVALID_ARGUMENT', `未知基础几何体类型: ${kind}`, {
|
|
46
|
+
details: { kind },
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const position = requireVec3(args.position);
|
|
50
|
+
let expectedRevision;
|
|
51
|
+
if (args.expectedRevision !== undefined) {
|
|
52
|
+
expectedRevision = requireFiniteNumber(args.expectedRevision, 'expectedRevision');
|
|
53
|
+
}
|
|
54
|
+
return { kind: kind, position, expectedRevision };
|
|
55
|
+
}
|
|
56
|
+
export function registerPrimitiveCommands(registry, runtime) {
|
|
57
|
+
registry.register({
|
|
58
|
+
name: 'primitives.create',
|
|
59
|
+
kind: 'mutation',
|
|
60
|
+
stateDomain: 'project',
|
|
61
|
+
undoable: 'single-step',
|
|
62
|
+
completion: 'mounted',
|
|
63
|
+
inputSchema: createInput,
|
|
64
|
+
outputSchema: createOutput,
|
|
65
|
+
errorCodes: [
|
|
66
|
+
'API_DISPOSED',
|
|
67
|
+
'INVALID_ARGUMENT',
|
|
68
|
+
'REVISION_CONFLICT',
|
|
69
|
+
'SCENE_UNAVAILABLE',
|
|
70
|
+
'RESOURCE_LOAD_FAILED',
|
|
71
|
+
'INTERNAL_ERROR',
|
|
72
|
+
],
|
|
73
|
+
validate: validateCreate,
|
|
74
|
+
execute: async (args) => {
|
|
75
|
+
runtime.assertActive();
|
|
76
|
+
await runtime.project.ready;
|
|
77
|
+
if (args.expectedRevision !== undefined) {
|
|
78
|
+
runtime.assertRevision(args.expectedRevision);
|
|
79
|
+
}
|
|
80
|
+
const createPrimitive = runtime.handlers.createPrimitive;
|
|
81
|
+
if (!createPrimitive) {
|
|
82
|
+
throw new AgentApiError('SCENE_UNAVAILABLE', 'Scene Runtime 未绑定 createPrimitive,无法创建基础几何体');
|
|
83
|
+
}
|
|
84
|
+
const placed = createPrimitive({ kind: args.kind, position: args.position });
|
|
85
|
+
try {
|
|
86
|
+
await placed.persisted;
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
runtime.assertActive();
|
|
90
|
+
throw new AgentApiError('RESOURCE_LOAD_FAILED', `基础几何体挂载失败: ${args.kind}`, {
|
|
91
|
+
details: {
|
|
92
|
+
kind: args.kind,
|
|
93
|
+
cause: error instanceof Error ? error.message : String(error),
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
runtime.assertActive();
|
|
98
|
+
const objectId = formatSceneObjectId('model', placed.key);
|
|
99
|
+
let mounted;
|
|
100
|
+
try {
|
|
101
|
+
mounted = getSceneObjectSummary(runtime.sheet, objectId).mounted;
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
throw new AgentApiError('INTERNAL_ERROR', `放置已提交但场景对象不可见: ${objectId}`, {
|
|
105
|
+
details: {
|
|
106
|
+
objectId,
|
|
107
|
+
cause: error instanceof Error ? error.message : String(error),
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (!mounted) {
|
|
112
|
+
throw new AgentApiError('INTERNAL_ERROR', `放置已提交但 SheetObject 未登记: ${objectId}`, { details: { objectId } });
|
|
113
|
+
}
|
|
114
|
+
return { objectId, revision: await runtime.nextRevision() };
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"primitives.test.d.ts","sourceRoot":"","sources":["../../../src/agent/commands/primitives.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { getProject, types as t, val } from '@dreamerbird/core';
|
|
2
|
+
import { globals } from '@dreamerbird/core/globals';
|
|
3
|
+
import { PLACEMENTS_REGISTRY_KEY } from '../../PlacementManager';
|
|
4
|
+
import { createCameraStudioApi } from '../api';
|
|
5
|
+
import { formatSceneObjectId } from '../objectIds';
|
|
6
|
+
import { AgentCommandRegistry } from '../registry';
|
|
7
|
+
import { createAgentRuntime } from '../runtime';
|
|
8
|
+
import { registerSceneSheetObject, unregisterSceneSheetObject, } from '../runtime/objectRuntime';
|
|
9
|
+
import { registerPrimitiveCommands } from './primitives';
|
|
10
|
+
let projectSeq = 0;
|
|
11
|
+
const cleanups = [];
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
while (cleanups.length)
|
|
14
|
+
cleanups.pop()();
|
|
15
|
+
});
|
|
16
|
+
const POSITION = { x: 0, y: 0, z: 0 };
|
|
17
|
+
function deferred() {
|
|
18
|
+
let resolve;
|
|
19
|
+
const promise = new Promise((res) => {
|
|
20
|
+
resolve = res;
|
|
21
|
+
});
|
|
22
|
+
return { promise, resolve };
|
|
23
|
+
}
|
|
24
|
+
function setup() {
|
|
25
|
+
const project = getProject(`agent-primitives-${++projectSeq}`, {
|
|
26
|
+
state: {
|
|
27
|
+
definitionVersion: globals.currentProjectStateDefinitionVersion,
|
|
28
|
+
sheetsById: {
|
|
29
|
+
Scene: {
|
|
30
|
+
staticOverrides: { byObject: {} },
|
|
31
|
+
sequence: {
|
|
32
|
+
type: 'PositionalSequence',
|
|
33
|
+
length: 10,
|
|
34
|
+
subUnitsPerUnit: 30,
|
|
35
|
+
tracksByObject: {},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
const sheet = project.sheet('Scene');
|
|
42
|
+
let notifyHistoric = () => { };
|
|
43
|
+
const runtime = createAgentRuntime({
|
|
44
|
+
project,
|
|
45
|
+
sheet,
|
|
46
|
+
library: {},
|
|
47
|
+
getStudio: () => undefined,
|
|
48
|
+
subscribeHistoric: (listener) => {
|
|
49
|
+
notifyHistoric = listener;
|
|
50
|
+
return () => { };
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
const controller = createCameraStudioApi({
|
|
54
|
+
buildRegistry: (currentRuntime) => {
|
|
55
|
+
const registry = new AgentCommandRegistry();
|
|
56
|
+
registerPrimitiveCommands(registry, currentRuntime);
|
|
57
|
+
return registry;
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
controller.activate(runtime);
|
|
61
|
+
cleanups.push(() => controller.dispose());
|
|
62
|
+
const createPrimitive = jest.fn();
|
|
63
|
+
return {
|
|
64
|
+
api: controller.api,
|
|
65
|
+
controller,
|
|
66
|
+
sheet,
|
|
67
|
+
runtime,
|
|
68
|
+
createPrimitive,
|
|
69
|
+
notifyHistoric: () => notifyHistoric(),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function bindCreatePrimitive(controller, createPrimitive, key, persisted) {
|
|
73
|
+
createPrimitive.mockReturnValue({ key, persisted });
|
|
74
|
+
const unbind = controller.bindSceneHandlers({
|
|
75
|
+
createPrimitive: (args) => createPrimitive(args),
|
|
76
|
+
});
|
|
77
|
+
cleanups.push(unbind);
|
|
78
|
+
}
|
|
79
|
+
function mountPrimitive(sheet, key) {
|
|
80
|
+
const registryObj = sheet.object(PLACEMENTS_REGISTRY_KEY, { list: t.string('[]') }, { hideFromOutline: true });
|
|
81
|
+
registryObj.initialValue = {
|
|
82
|
+
list: JSON.stringify([{ key, primitive: 'box', position: POSITION }]),
|
|
83
|
+
};
|
|
84
|
+
const obj = sheet.object(key, {
|
|
85
|
+
position: t.compound({ x: t.number(0), y: t.number(0), z: t.number(0) }),
|
|
86
|
+
});
|
|
87
|
+
const id = formatSceneObjectId('model', key);
|
|
88
|
+
registerSceneSheetObject(id, obj);
|
|
89
|
+
cleanups.push(() => unregisterSceneSheetObject(id, obj));
|
|
90
|
+
}
|
|
91
|
+
async function untilCreatePrimitiveCalled(createPrimitive) {
|
|
92
|
+
for (let i = 0; i < 50 && createPrimitive.mock.calls.length === 0; i++) {
|
|
93
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
94
|
+
}
|
|
95
|
+
expect(createPrimitive).toHaveBeenCalled();
|
|
96
|
+
}
|
|
97
|
+
test('api.primitives.create resolves after mounting and persists the primitive entry', async () => {
|
|
98
|
+
const { api, controller, sheet, createPrimitive, notifyHistoric } = setup();
|
|
99
|
+
const mount = deferred();
|
|
100
|
+
bindCreatePrimitive(controller, createPrimitive, 'Box', mount.promise);
|
|
101
|
+
await api.ready;
|
|
102
|
+
let resolved = false;
|
|
103
|
+
const promise = api.primitives
|
|
104
|
+
.create({ kind: 'box', position: POSITION })
|
|
105
|
+
.then((result) => {
|
|
106
|
+
resolved = true;
|
|
107
|
+
return result;
|
|
108
|
+
});
|
|
109
|
+
await untilCreatePrimitiveCalled(createPrimitive);
|
|
110
|
+
expect(createPrimitive).toHaveBeenCalledWith({
|
|
111
|
+
kind: 'box',
|
|
112
|
+
position: POSITION,
|
|
113
|
+
});
|
|
114
|
+
expect(resolved).toBe(false);
|
|
115
|
+
mountPrimitive(sheet, 'Box');
|
|
116
|
+
notifyHistoric();
|
|
117
|
+
mount.resolve();
|
|
118
|
+
await expect(promise).resolves.toEqual({
|
|
119
|
+
objectId: 'model:Box',
|
|
120
|
+
revision: 2,
|
|
121
|
+
});
|
|
122
|
+
const registryObj = sheet.object(PLACEMENTS_REGISTRY_KEY, {
|
|
123
|
+
list: t.string('[]'),
|
|
124
|
+
});
|
|
125
|
+
expect(JSON.parse(val(registryObj.props.list))).toEqual([
|
|
126
|
+
{ key: 'Box', primitive: 'box', position: POSITION },
|
|
127
|
+
]);
|
|
128
|
+
});
|
|
129
|
+
test('api.primitives.create rejects an unknown kind before any handler call', async () => {
|
|
130
|
+
const { api, controller, createPrimitive } = setup();
|
|
131
|
+
bindCreatePrimitive(controller, createPrimitive, 'Box', Promise.resolve());
|
|
132
|
+
await api.ready;
|
|
133
|
+
await expect(api.primitives.create({ kind: 'cone', position: POSITION })).rejects.toMatchObject({ code: 'INVALID_ARGUMENT' });
|
|
134
|
+
expect(createPrimitive).not.toHaveBeenCalled();
|
|
135
|
+
});
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
* 任何变更必须先改 spec 第 9 节,再同步本清单——契约覆盖测试
|
|
5
5
|
* (contractCoverage.test.ts)对缺少与多出都失败。
|
|
6
6
|
*/
|
|
7
|
-
export declare const EXPECTED_AGENT_COMMANDS: readonly ["scene.getSnapshot", "selection.get", "selection.selectObject", "selection.clear", "objects.list", "objects.get", "objects.update", "objects.delete", "models.create", "assets.list", "assets.get", "assets.importModel", "assets.rename", "assets.delete", "poses.apply", "poses.applyCustom", "poses.clear", "poses.saveCurrent", "poses.setGesture", "poses.session.start", "poses.session.commit", "poses.session.cancel", "animations.apply", "animations.clear", "animations.getStatus", "cameras.create", "cameras.setActive", "cameras.setAimTarget", "cameras.bindPath", "cameras.unbindPath", "anchors.create", "anchors.setParent", "anchors.clearParent", "paths.listPresets", "paths.createPreset", "paths.addPoint", "paths.updatePoint", "paths.deletePoint", "paths.setPointTiming", "paths.sample", "paths.session.startEditing", "paths.session.exitEditing", "paths.session.selectPoint", "sequence.getState", "sequence.play", "sequence.pause", "sequence.seek", "sequence.setLength", "keyframes.list", "keyframes.set", "keyframes.move", "keyframes.delete", "history.undo", "history.redo", "view.getState", "view.setShotView", "view.setPipVisible", "view.orbit", "view.pan", "view.dolly", "view.reset", "ui.hide", "ui.restore", "ui.setLeftStripHidden", "ui.openPanel", "ui.closePanel", "ui.setGizmoMode", "project.exportState", "exports.startVideo", "jobs.get", "jobs.cancel"];
|
|
7
|
+
export declare const EXPECTED_AGENT_COMMANDS: readonly ["scene.getSnapshot", "selection.get", "selection.selectObject", "selection.clear", "objects.list", "objects.get", "objects.update", "objects.delete", "models.create", "models.retry", "models.replace", "primitives.create", "materials.list", "materials.update", "assets.list", "assets.get", "assets.importModel", "assets.importModels", "assets.rename", "assets.delete", "poses.apply", "poses.applyCustom", "poses.clear", "poses.saveCurrent", "poses.setGesture", "poses.session.start", "poses.session.commit", "poses.session.cancel", "animations.apply", "animations.clear", "animations.getStatus", "cameras.create", "cameras.setActive", "cameras.setAimTarget", "cameras.bindPath", "cameras.unbindPath", "anchors.create", "anchors.setParent", "anchors.clearParent", "paths.listPresets", "paths.createPreset", "paths.addPoint", "paths.updatePoint", "paths.deletePoint", "paths.setPointTiming", "paths.sample", "paths.session.startEditing", "paths.session.exitEditing", "paths.session.selectPoint", "sequence.getState", "sequence.play", "sequence.pause", "sequence.seek", "sequence.setLength", "keyframes.list", "keyframes.set", "keyframes.move", "keyframes.delete", "history.undo", "history.redo", "view.getState", "view.setShotView", "view.setPipVisible", "view.orbit", "view.pan", "view.dolly", "view.reset", "ui.hide", "ui.restore", "ui.setLeftStripHidden", "ui.openPanel", "ui.closePanel", "ui.setGizmoMode", "project.exportState", "exports.startVideo", "jobs.get", "jobs.cancel"];
|
|
8
8
|
export type ExpectedAgentCommand = (typeof EXPECTED_AGENT_COMMANDS)[number];
|
|
9
9
|
//# sourceMappingURL=expectedCommands.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expectedCommands.d.ts","sourceRoot":"","sources":["../../src/agent/expectedCommands.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB
|
|
1
|
+
{"version":3,"file":"expectedCommands.d.ts","sourceRoot":"","sources":["../../src/agent/expectedCommands.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,m9CA8E1B,CAAA;AAEV,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAA"}
|
|
@@ -14,9 +14,15 @@ export const EXPECTED_AGENT_COMMANDS = [
|
|
|
14
14
|
'objects.update',
|
|
15
15
|
'objects.delete',
|
|
16
16
|
'models.create',
|
|
17
|
+
'models.retry',
|
|
18
|
+
'models.replace',
|
|
19
|
+
'primitives.create',
|
|
20
|
+
'materials.list',
|
|
21
|
+
'materials.update',
|
|
17
22
|
'assets.list',
|
|
18
23
|
'assets.get',
|
|
19
24
|
'assets.importModel',
|
|
25
|
+
'assets.importModels',
|
|
20
26
|
'assets.rename',
|
|
21
27
|
'assets.delete',
|
|
22
28
|
'poses.apply',
|
|
@@ -28,6 +28,8 @@ export declare function assertStaticPropsWritable(sheetObject: ISheetObject<$Int
|
|
|
28
28
|
* SCENE_UNAVAILABLE(不静默返回,spec 8.3)。
|
|
29
29
|
*/
|
|
30
30
|
export declare function setStaticProps(sheetObject: ISheetObject<$IntentionalAny>, props: Record<string, unknown>): void;
|
|
31
|
+
export declare function assertStaticPropsWithLeafGuardWritable(sheetObject: ISheetObject<$IntentionalAny>, props: Record<string, unknown>, guardedPropPaths: string[]): void;
|
|
32
|
+
export declare function setStaticPropsWithLeafGuard(sheetObject: ISheetObject<$IntentionalAny>, props: Record<string, unknown>, guardedPropPaths: string[]): void;
|
|
31
33
|
/**
|
|
32
34
|
* 领域静态写入 + 坐标定格同事务(2026-10-19,Agent API F1 修复):
|
|
33
35
|
* 绑定/父级切换类命令(setParent/clearParent/unbindPath/setAimTarget 解除)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"propAccess.d.ts","sourceRoot":"","sources":["../../src/agent/propAccess.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,mBAAmB,CAAA;AACnD,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,gCAAgC,CAAA;AACnE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,wBAAwB,CAAA;AAInD;;;GAGG;AACH,QAAA,MAAM,gBAAgB,
|
|
1
|
+
{"version":3,"file":"propAccess.d.ts","sourceRoot":"","sources":["../../src/agent/propAccess.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,mBAAmB,CAAA;AACnD,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,gCAAgC,CAAA;AACnE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,wBAAwB,CAAA;AAInD;;;GAGG;AACH,QAAA,MAAM,gBAAgB,aAYpB,CAAA;AAEF,OAAO,EAAC,gBAAgB,EAAC,CAAA;AAEzB,6DAA6D;AAC7D,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,YAAY,CAAC,eAAe,CAAC,EAClC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,eAAe,CAAC,CAM1B;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,YAAY,CAAC,eAAe,CAAC,EAClC,QAAQ,EAAE,MAAM,GACf,OAAO,CAaT;AA4FD;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,YAAY,CAAC,eAAe,CAAC,EAC1C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,IAAI,CAyBN;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,YAAY,CAAC,eAAe,CAAC,EAC1C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,IAAI,CAGN;AAED,wBAAgB,sCAAsC,CACpD,WAAW,EAAE,YAAY,CAAC,eAAe,CAAC,EAC1C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,gBAAgB,EAAE,MAAM,EAAE,GACzB,IAAI,CAmBN;AAED,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,YAAY,CAAC,eAAe,CAAC,EAC1C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,gBAAgB,EAAE,MAAM,EAAE,GACzB,IAAI,CAGN;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,YAAY,CAAC,eAAe,CAAC,EAC1C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,IAAI,CAGN"}
|
package/dist/agent/propAccess.js
CHANGED
|
@@ -25,6 +25,7 @@ const domainOwnedProps = new Set([
|
|
|
25
25
|
'gestureL',
|
|
26
26
|
'gestureR',
|
|
27
27
|
'animation',
|
|
28
|
+
'materialOverrides',
|
|
28
29
|
'aimTarget',
|
|
29
30
|
'pathKey',
|
|
30
31
|
'parent',
|
|
@@ -154,6 +155,26 @@ export function setStaticProps(sheetObject, props) {
|
|
|
154
155
|
assertStaticPropsWritable(sheetObject, props);
|
|
155
156
|
writePropsInTransaction(sheetObject, props);
|
|
156
157
|
}
|
|
158
|
+
export function assertStaticPropsWithLeafGuardWritable(sheetObject, props, guardedPropPaths) {
|
|
159
|
+
const current = sheetObject.value;
|
|
160
|
+
for (const [key, value] of Object.entries(props)) {
|
|
161
|
+
if (!current || !(key in current)) {
|
|
162
|
+
throw new AgentApiError('INVALID_ARGUMENT', `未知属性: ${key}`, {
|
|
163
|
+
details: { prop: key },
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
validateValueShape(key, current[key], value);
|
|
167
|
+
}
|
|
168
|
+
for (const propPath of guardedPropPaths) {
|
|
169
|
+
if (isPropSequenced(sheetObject, propPath)) {
|
|
170
|
+
throw new AgentApiError('INVALID_STATE', `属性 ${propPath} 已建轨,请改用 keyframes.* 写入`, { details: { prop: propPath } });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
export function setStaticPropsWithLeafGuard(sheetObject, props, guardedPropPaths) {
|
|
175
|
+
assertStaticPropsWithLeafGuardWritable(sheetObject, props, guardedPropPaths);
|
|
176
|
+
writePropsInTransaction(sheetObject, props);
|
|
177
|
+
}
|
|
157
178
|
/**
|
|
158
179
|
* 领域静态写入 + 坐标定格同事务(2026-10-19,Agent API F1 修复):
|
|
159
180
|
* 绑定/父级切换类命令(setParent/clearParent/unbindPath/setAimTarget 解除)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registerCommands.d.ts","sourceRoot":"","sources":["../../src/agent/registerCommands.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,YAAY,CAAA;AACpD,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"registerCommands.d.ts","sourceRoot":"","sources":["../../src/agent/registerCommands.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,YAAY,CAAA;AACpD,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,WAAW,CAAA;AAgC3C;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,EAAE,YAAY,GACpB,IAAI,CAoCN"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 全量 Agent 命令注册(2026-10-19,Task 15):按 Task 4–14 落地顺序
|
|
3
|
-
* 注册全部
|
|
3
|
+
* 注册全部 20 个命令组(spec §9 命令面,75 条命令),供生产会话与
|
|
4
4
|
* 契约测试共用同一个注册入口。
|
|
5
5
|
*
|
|
6
6
|
* 重复命令兜底:registry.register 本身按名拒重(INVALID_STATE),注册
|
|
@@ -20,6 +20,8 @@ import { registerHistoryCommands } from './commands/history';
|
|
|
20
20
|
import { registerKeyframeCommands } from './commands/keyframes';
|
|
21
21
|
// Task 8:模型创建 + 资产管理 + 任务查询/取消
|
|
22
22
|
import { registerModelCommands } from './commands/models';
|
|
23
|
+
import { registerPrimitiveCommands } from './commands/primitives';
|
|
24
|
+
import { registerMaterialCommands } from './commands/materials';
|
|
23
25
|
import { registerAssetCommands } from './commands/assets';
|
|
24
26
|
import { registerJobCommands } from './commands/jobs';
|
|
25
27
|
// Task 9:姿势/手势 + 动画
|
|
@@ -54,6 +56,8 @@ export function registerAllAgentCommands(registry, runtime) {
|
|
|
54
56
|
registerKeyframeCommands(registry, runtime);
|
|
55
57
|
// Task 8
|
|
56
58
|
registerModelCommands(registry, runtime);
|
|
59
|
+
registerPrimitiveCommands(registry, runtime);
|
|
60
|
+
registerMaterialCommands(registry, runtime);
|
|
57
61
|
registerAssetCommands(registry, runtime);
|
|
58
62
|
registerJobCommands(registry, runtime);
|
|
59
63
|
// Task 9
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { ISheetObject } from '@dreamerbird/core';
|
|
11
11
|
import type { SceneObjectId } from '../types';
|
|
12
|
+
export declare function subscribeSceneSheetObjects(listener: () => void): () => void;
|
|
13
|
+
export declare function clearSceneSheetObjects(): void;
|
|
12
14
|
/** 登记某业务对象当前挂载的 SheetObject(objRef 填充时) */
|
|
13
15
|
export declare function registerSceneSheetObject(id: SceneObjectId, obj: ISheetObject<any>): void;
|
|
14
16
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"objectRuntime.d.ts","sourceRoot":"","sources":["../../../src/agent/runtime/objectRuntime.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,mBAAmB,CAAA;AACnD,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"objectRuntime.d.ts","sourceRoot":"","sources":["../../../src/agent/runtime/objectRuntime.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,mBAAmB,CAAA;AACnD,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,UAAU,CAAA;AAS3C,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAG3E;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAG7C;AAED,2CAA2C;AAC3C,wBAAgB,wBAAwB,CACtC,EAAE,EAAE,aAAa,EACjB,GAAG,EAAE,YAAY,CAAC,GAAG,CAAC,GACrB,IAAI,CAGN;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,EAAE,EAAE,aAAa,EACjB,GAAG,CAAC,EAAE,YAAY,CAAC,GAAG,CAAC,GACtB,IAAI,CAGN;AAED,oDAAoD;AACpD,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,aAAa,GAChB,YAAY,CAAC,GAAG,CAAC,GAAG,SAAS,CAE/B;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,aAAa,GAAG,SAAS,CAK5E"}
|
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
const sceneSheetObjects = new Map();
|
|
2
|
+
const listeners = new Set();
|
|
3
|
+
function emitChange() {
|
|
4
|
+
listeners.forEach((listener) => listener());
|
|
5
|
+
}
|
|
6
|
+
export function subscribeSceneSheetObjects(listener) {
|
|
7
|
+
listeners.add(listener);
|
|
8
|
+
return () => listeners.delete(listener);
|
|
9
|
+
}
|
|
10
|
+
export function clearSceneSheetObjects() {
|
|
11
|
+
sceneSheetObjects.clear();
|
|
12
|
+
emitChange();
|
|
13
|
+
}
|
|
2
14
|
/** 登记某业务对象当前挂载的 SheetObject(objRef 填充时) */
|
|
3
15
|
export function registerSceneSheetObject(id, obj) {
|
|
4
16
|
sceneSheetObjects.set(id, obj);
|
|
17
|
+
emitChange();
|
|
5
18
|
}
|
|
6
19
|
/**
|
|
7
20
|
* 按 id 清理登记(objRef 清空/组件卸载时)。传入 obj 时仅当登记的还是
|
|
@@ -10,7 +23,8 @@ export function registerSceneSheetObject(id, obj) {
|
|
|
10
23
|
export function unregisterSceneSheetObject(id, obj) {
|
|
11
24
|
if (obj && sceneSheetObjects.get(id) !== obj)
|
|
12
25
|
return;
|
|
13
|
-
sceneSheetObjects.delete(id)
|
|
26
|
+
if (sceneSheetObjects.delete(id))
|
|
27
|
+
emitChange();
|
|
14
28
|
}
|
|
15
29
|
/** 当前挂载的 SheetObject;未挂载(注册表有条目但组件未起)为 undefined */
|
|
16
30
|
export function getSceneSheetObject(id) {
|
package/dist/agent/runtime.d.ts
CHANGED
|
@@ -30,6 +30,7 @@ export type AgentRuntime = {
|
|
|
30
30
|
readonly library: Library;
|
|
31
31
|
readonly getStudio: () => IStudio | undefined;
|
|
32
32
|
readonly jobs: AgentJobManager;
|
|
33
|
+
subscribeHistoric(listener: () => void): () => void;
|
|
33
34
|
/** 当前会话的 historic revision,从 1 开始 */
|
|
34
35
|
readonly revision: number;
|
|
35
36
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/agent/runtime.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAC,MAAM,mBAAmB,CAAA;AAGhE,OAAO,EAAC,eAAe,EAAC,MAAM,QAAQ,CAAA;AACtC,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,yBAAyB,CAAA;AAyCpD;;;;GAIG;AAEH,MAAM,WAAW,yBAAyB;CAAG;AAE7C,KAAK,QAAQ,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAA;AAElD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,QAAQ,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,OAAO,GAAG,SAAS,CAAA;IACpC;2FACuF;IACvF,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAA;CACxD,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAA;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,OAAO,GAAG,SAAS,CAAA;IAC7C,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;IAC9B,qCAAqC;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB;;;;;OAKG;IACH,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;IAC/B,kFAAkF;IAClF,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7B,iCAAiC;IACjC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAA;IACrC,6DAA6D;IAC7D,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACtC,mBAAmB;IACnB,YAAY,IAAI,IAAI,CAAA;IACpB,uCAAuC;IACvC,aAAa,IAAI,IAAI,CAAA;IACrB,wDAAwD;IACxD,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,IAAI,CAAA;IAC5C;qEACiE;IACjE,QAAQ,IAAI,YAAY,CAAA;IACxB,qDAAqD;IACrD,SAAS,IAAI,IAAI,CAAA;IACjB;8DAC0D;IAC1D,OAAO,IAAI,IAAI,CAAA;CAChB,CAAA;
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/agent/runtime.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAC,MAAM,mBAAmB,CAAA;AAGhE,OAAO,EAAC,eAAe,EAAC,MAAM,QAAQ,CAAA;AACtC,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,yBAAyB,CAAA;AAyCpD;;;;GAIG;AAEH,MAAM,WAAW,yBAAyB;CAAG;AAE7C,KAAK,QAAQ,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAA;AAElD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,QAAQ,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,OAAO,GAAG,SAAS,CAAA;IACpC;2FACuF;IACvF,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAA;CACxD,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAA;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,OAAO,GAAG,SAAS,CAAA;IAC7C,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;IAC9B,iBAAiB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;IACnD,qCAAqC;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB;;;;;OAKG;IACH,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;IAC/B,kFAAkF;IAClF,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7B,iCAAiC;IACjC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAA;IACrC,6DAA6D;IAC7D,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACtC,mBAAmB;IACnB,YAAY,IAAI,IAAI,CAAA;IACpB,uCAAuC;IACvC,aAAa,IAAI,IAAI,CAAA;IACrB,wDAAwD;IACxD,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,IAAI,CAAA;IAC5C;qEACiE;IACjE,QAAQ,IAAI,YAAY,CAAA;IACxB,qDAAqD;IACrD,SAAS,IAAI,IAAI,CAAA;IACjB;8DAC0D;IAC1D,OAAO,IAAI,IAAI,CAAA;CAChB,CAAA;AAuED,0DAA0D;AAC1D,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAOnE;AAsHD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,YAAY,CA0BvE"}
|
package/dist/agent/runtime.js
CHANGED
|
@@ -87,6 +87,7 @@ function makeRuntime(core, generation) {
|
|
|
87
87
|
library: core.library,
|
|
88
88
|
getStudio: core.getStudio,
|
|
89
89
|
jobs: core.jobs,
|
|
90
|
+
subscribeHistoric: core.subscribeHistoric,
|
|
90
91
|
get revision() {
|
|
91
92
|
return core.revision;
|
|
92
93
|
},
|
|
@@ -197,6 +198,7 @@ export function createAgentRuntime(deps) {
|
|
|
197
198
|
revision: 1,
|
|
198
199
|
currentGeneration: first,
|
|
199
200
|
generations: new Set([first]),
|
|
201
|
+
subscribeHistoric: deps.subscribeHistoric,
|
|
200
202
|
unsubscribeHistoric: () => { },
|
|
201
203
|
};
|
|
202
204
|
// 订阅必须在 core 建好之后:真实 subscribeHistoric 走 core
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { Object3D } from 'three';
|
|
2
|
-
/** 递归释放对象树的 GPU
|
|
3
|
-
export declare function disposeObjectTree(root: Object3D
|
|
2
|
+
/** 递归释放对象树的 GPU 资源;纹理默认随材质释放,共享纹理的克隆实例可关闭 */
|
|
3
|
+
export declare function disposeObjectTree(root: Object3D, options?: {
|
|
4
|
+
disposeTextures?: boolean;
|
|
5
|
+
}): void;
|
|
4
6
|
//# sourceMappingURL=dispose.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispose.d.ts","sourceRoot":"","sources":["../../src/assetLibrary/dispose.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,QAAQ,EAAU,MAAM,OAAO,CAAA;AAEtD,
|
|
1
|
+
{"version":3,"file":"dispose.d.ts","sourceRoot":"","sources":["../../src/assetLibrary/dispose.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,QAAQ,EAAU,MAAM,OAAO,CAAA;AAEtD,6CAA6C;AAC7C,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,QAAQ,EACd,OAAO,GAAE;IAAC,eAAe,CAAC,EAAE,OAAO,CAAA;CAAM,GACxC,IAAI,CAuBN"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/** 递归释放对象树的 GPU
|
|
2
|
-
export function disposeObjectTree(root) {
|
|
1
|
+
/** 递归释放对象树的 GPU 资源;纹理默认随材质释放,共享纹理的克隆实例可关闭 */
|
|
2
|
+
export function disposeObjectTree(root, options = {}) {
|
|
3
3
|
root.traverse((o) => {
|
|
4
4
|
const mesh = o;
|
|
5
5
|
if (!mesh.isMesh)
|
|
@@ -11,9 +11,11 @@ export function disposeObjectTree(root) {
|
|
|
11
11
|
? [mesh.material]
|
|
12
12
|
: [];
|
|
13
13
|
for (const m of mats) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
v
|
|
14
|
+
if (options.disposeTextures !== false) {
|
|
15
|
+
for (const v of Object.values(m)) {
|
|
16
|
+
if (v?.isTexture)
|
|
17
|
+
v.dispose();
|
|
18
|
+
}
|
|
17
19
|
}
|
|
18
20
|
m.dispose();
|
|
19
21
|
}
|
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
import { Group } from 'three';
|
|
2
2
|
import type { AnimationClip, Object3D } from 'three';
|
|
3
|
+
/**
|
|
4
|
+
* 场景单位 = 米(2026-10-21 起,替代此前「最长边统一拉成 5 单位」的
|
|
5
|
+
* 归一化约定)。glTF 标准本来就是米,人高 1.8 单位、网格 1 小格 = 1 米,
|
|
6
|
+
* 模型之间保持真实世界的相对大小(车 4.5 / 人 1.8 / 杯子 0.1)。
|
|
7
|
+
* PlacementManager 的 useNormalizedModel 用同一套换算兜底未烘焙来源。
|
|
8
|
+
*/
|
|
9
|
+
export declare const SCENE_UNIT_METERS = 1;
|
|
10
|
+
/**
|
|
11
|
+
* 厘米源判定阈值:最长边超过这个数就按厘米源处理(÷100)。
|
|
12
|
+
* Mixamo 等 FBX 是厘米(人 180),标准 GLB 是米(人 1.8)。取 50 是因为
|
|
13
|
+
* 米制模型最长边到 50(=50 米,一栋楼)在本系统里罕见,而厘米源几乎
|
|
14
|
+
* 都远超(一个人就 180)。猜错的入口(超大道具/建筑)保留手动改缩放。
|
|
15
|
+
*/
|
|
16
|
+
export declare const CENTIMETER_SOURCE_THRESHOLD = 50;
|
|
17
|
+
/** 源尺寸最长边 → 米制换算系数(米源返回 1,厘米源返回 0.01) */
|
|
18
|
+
export declare function metricScaleFactor(maxDim: number): number;
|
|
19
|
+
/**
|
|
20
|
+
* 把「源单位 → 米」的换算系数烘进根节点 scale(入库前置)。
|
|
21
|
+
* 源文件单位五花八门(Mixamo FBX 是厘米、GLB 多是米),烘过之后任何
|
|
22
|
+
* 模型都是真实米制尺寸,放置时 theatre 对象的缩放属性才能以 1 为
|
|
23
|
+
* 干净基线(1 = 真实大小,2 = 两倍大)。只动根节点变换:蒙皮随骨骼
|
|
24
|
+
* 世界变换正确缩放,骨骼局部数据(动画轨道寻址的那层)不受影响。
|
|
25
|
+
* 返回应用的系数(1 = 本来就是米,没动)。
|
|
26
|
+
*/
|
|
27
|
+
export declare function bakeMetricScale(root: Object3D): number;
|
|
3
28
|
/**
|
|
4
29
|
* 移除无法导出的贴图(image 数据缺失)。
|
|
5
30
|
* FBX 常引用本机不存在的外部贴图文件,加载失败后留下 image 为空的 Texture,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exportGLB.d.ts","sourceRoot":"","sources":["../../src/assetLibrary/exportGLB.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"exportGLB.d.ts","sourceRoot":"","sources":["../../src/assetLibrary/exportGLB.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,EAAU,MAAM,OAAO,CAAA;AAChD,OAAO,KAAK,EAAC,aAAa,EAAQ,QAAQ,EAAU,MAAM,OAAO,CAAA;AAIjE;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,IAAI,CAAA;AAElC;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,KAAK,CAAA;AAE7C,yCAAyC;AACzC,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAStD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CA6B3D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,CAoBnD;AAgBD,0CAA0C;AAC1C,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,CAgBnE;AAED,6BAA6B;AAC7B,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,WAAW,CAAC,CAEtB"}
|
|
@@ -1,6 +1,44 @@
|
|
|
1
|
-
import { Bone, Group } from 'three';
|
|
1
|
+
import { Bone, Box3, Group, Vector3 } from 'three';
|
|
2
2
|
import { GLTFExporter } from 'three-stdlib';
|
|
3
3
|
import { compressGLBDraco } from './draco';
|
|
4
|
+
/**
|
|
5
|
+
* 场景单位 = 米(2026-10-21 起,替代此前「最长边统一拉成 5 单位」的
|
|
6
|
+
* 归一化约定)。glTF 标准本来就是米,人高 1.8 单位、网格 1 小格 = 1 米,
|
|
7
|
+
* 模型之间保持真实世界的相对大小(车 4.5 / 人 1.8 / 杯子 0.1)。
|
|
8
|
+
* PlacementManager 的 useNormalizedModel 用同一套换算兜底未烘焙来源。
|
|
9
|
+
*/
|
|
10
|
+
export const SCENE_UNIT_METERS = 1;
|
|
11
|
+
/**
|
|
12
|
+
* 厘米源判定阈值:最长边超过这个数就按厘米源处理(÷100)。
|
|
13
|
+
* Mixamo 等 FBX 是厘米(人 180),标准 GLB 是米(人 1.8)。取 50 是因为
|
|
14
|
+
* 米制模型最长边到 50(=50 米,一栋楼)在本系统里罕见,而厘米源几乎
|
|
15
|
+
* 都远超(一个人就 180)。猜错的入口(超大道具/建筑)保留手动改缩放。
|
|
16
|
+
*/
|
|
17
|
+
export const CENTIMETER_SOURCE_THRESHOLD = 50;
|
|
18
|
+
/** 源尺寸最长边 → 米制换算系数(米源返回 1,厘米源返回 0.01) */
|
|
19
|
+
export function metricScaleFactor(maxDim) {
|
|
20
|
+
return maxDim > CENTIMETER_SOURCE_THRESHOLD ? 0.01 : SCENE_UNIT_METERS;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 把「源单位 → 米」的换算系数烘进根节点 scale(入库前置)。
|
|
24
|
+
* 源文件单位五花八门(Mixamo FBX 是厘米、GLB 多是米),烘过之后任何
|
|
25
|
+
* 模型都是真实米制尺寸,放置时 theatre 对象的缩放属性才能以 1 为
|
|
26
|
+
* 干净基线(1 = 真实大小,2 = 两倍大)。只动根节点变换:蒙皮随骨骼
|
|
27
|
+
* 世界变换正确缩放,骨骼局部数据(动画轨道寻址的那层)不受影响。
|
|
28
|
+
* 返回应用的系数(1 = 本来就是米,没动)。
|
|
29
|
+
*/
|
|
30
|
+
export function bakeMetricScale(root) {
|
|
31
|
+
const box = new Box3().setFromObject(root);
|
|
32
|
+
const size = box.getSize(new Vector3());
|
|
33
|
+
const maxDim = Math.max(size.x, size.y, size.z);
|
|
34
|
+
if (!(maxDim > 0))
|
|
35
|
+
return 1;
|
|
36
|
+
const factor = metricScaleFactor(maxDim);
|
|
37
|
+
if (factor === 1)
|
|
38
|
+
return 1;
|
|
39
|
+
root.scale.multiplyScalar(factor);
|
|
40
|
+
return factor;
|
|
41
|
+
}
|
|
4
42
|
/**
|
|
5
43
|
* 移除无法导出的贴图(image 数据缺失)。
|
|
6
44
|
* FBX 常引用本机不存在的外部贴图文件,加载失败后留下 image 为空的 Texture,
|
|
@@ -75,6 +113,10 @@ export function exportModelGLB(root) {
|
|
|
75
113
|
if (stripped > 0) {
|
|
76
114
|
console.warn(`[assetLibrary] ${stripped} 张贴图数据无效(源文件引用的贴图缺失或加载失败),已移除后继续导出,模型将以灰模/部分贴图入库`);
|
|
77
115
|
}
|
|
116
|
+
const factor = bakeMetricScale(root);
|
|
117
|
+
if (factor !== 1) {
|
|
118
|
+
console.info(`[assetLibrary] 已把源尺寸换算成米烘进模型(系数 ${factor.toFixed(4)}),放置时缩放基线为 1 = 真实大小`);
|
|
119
|
+
}
|
|
78
120
|
return exportGLB(root, []).then(compressGLBDraco);
|
|
79
121
|
}
|
|
80
122
|
/** 动作入库:骨骼树克隆 + 单条动画,不含网格 */
|