freeform-modeling-mcp 1.0.26

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 (81) hide show
  1. package/README.md +61 -0
  2. package/index.cjs +21 -0
  3. package/package.json +48 -0
  4. package/src/cli.ts +47 -0
  5. package/src/commands/start.ts +88 -0
  6. package/src/commands/status.ts +81 -0
  7. package/src/dev.ts +24 -0
  8. package/src/lib/fileproxy/index.ts +505 -0
  9. package/src/lib/fileproxy/proxy-server.js +347 -0
  10. package/src/lib/gltf2obj/compress.js +33 -0
  11. package/src/lib/gltf2obj/engine/core/core.js +34 -0
  12. package/src/lib/gltf2obj/engine/core/eventnotifier.js +39 -0
  13. package/src/lib/gltf2obj/engine/core/taskrunner.js +88 -0
  14. package/src/lib/gltf2obj/engine/export/exporter.js +38 -0
  15. package/src/lib/gltf2obj/engine/export/exporterbase.js +86 -0
  16. package/src/lib/gltf2obj/engine/export/exportermodel.js +117 -0
  17. package/src/lib/gltf2obj/engine/export/exporterobj.js +147 -0
  18. package/src/lib/gltf2obj/engine/geometry/box3d.js +60 -0
  19. package/src/lib/gltf2obj/engine/geometry/coord2d.js +35 -0
  20. package/src/lib/gltf2obj/engine/geometry/coord3d.js +126 -0
  21. package/src/lib/gltf2obj/engine/geometry/coord4d.js +15 -0
  22. package/src/lib/gltf2obj/engine/geometry/geometry.js +56 -0
  23. package/src/lib/gltf2obj/engine/geometry/matrix.js +440 -0
  24. package/src/lib/gltf2obj/engine/geometry/octree.js +160 -0
  25. package/src/lib/gltf2obj/engine/geometry/quaternion.js +83 -0
  26. package/src/lib/gltf2obj/engine/geometry/transformation.js +63 -0
  27. package/src/lib/gltf2obj/engine/geometry/tween.js +31 -0
  28. package/src/lib/gltf2obj/engine/import/importer.js +270 -0
  29. package/src/lib/gltf2obj/engine/import/importerbase.js +115 -0
  30. package/src/lib/gltf2obj/engine/import/importerfiles.js +139 -0
  31. package/src/lib/gltf2obj/engine/import/importergltf.js +1045 -0
  32. package/src/lib/gltf2obj/engine/import/importerutils.js +102 -0
  33. package/src/lib/gltf2obj/engine/io/binaryreader.js +93 -0
  34. package/src/lib/gltf2obj/engine/io/binarywriter.js +92 -0
  35. package/src/lib/gltf2obj/engine/io/bufferutils.js +85 -0
  36. package/src/lib/gltf2obj/engine/io/externallibs.js +42 -0
  37. package/src/lib/gltf2obj/engine/io/fileutils.js +120 -0
  38. package/src/lib/gltf2obj/engine/io/textwriter.js +41 -0
  39. package/src/lib/gltf2obj/engine/main.js +19 -0
  40. package/src/lib/gltf2obj/engine/model/color.js +130 -0
  41. package/src/lib/gltf2obj/engine/model/generator.js +433 -0
  42. package/src/lib/gltf2obj/engine/model/material.js +243 -0
  43. package/src/lib/gltf2obj/engine/model/mesh.js +173 -0
  44. package/src/lib/gltf2obj/engine/model/meshbuffer.js +233 -0
  45. package/src/lib/gltf2obj/engine/model/meshinstance.js +128 -0
  46. package/src/lib/gltf2obj/engine/model/meshutils.js +64 -0
  47. package/src/lib/gltf2obj/engine/model/model.js +195 -0
  48. package/src/lib/gltf2obj/engine/model/modelfinalization.js +377 -0
  49. package/src/lib/gltf2obj/engine/model/modelutils.js +117 -0
  50. package/src/lib/gltf2obj/engine/model/node.js +178 -0
  51. package/src/lib/gltf2obj/engine/model/object.js +90 -0
  52. package/src/lib/gltf2obj/engine/model/property.js +86 -0
  53. package/src/lib/gltf2obj/engine/model/quantities.js +46 -0
  54. package/src/lib/gltf2obj/engine/model/topology.js +139 -0
  55. package/src/lib/gltf2obj/engine/model/triangle.js +99 -0
  56. package/src/lib/gltf2obj/engine/threejs/threemodelloader.js +85 -0
  57. package/src/lib/gltf2obj/handler.js +63 -0
  58. package/src/lib/gltf2obj/index.js +47 -0
  59. package/src/lib/logger.ts +304 -0
  60. package/src/lib/print.ts +37 -0
  61. package/src/lib/utils.ts +34 -0
  62. package/src/lib/wsbridge/bridge.ts +639 -0
  63. package/src/lib/wsbridge/lock.ts +258 -0
  64. package/src/llmClient.ts +245 -0
  65. package/src/prompt.ts +187 -0
  66. package/src/server.ts +125 -0
  67. package/src/tools/assets-tool.ts +314 -0
  68. package/src/tools/basic-tools.ts +531 -0
  69. package/src/tools/index.ts +2 -0
  70. package/src/tools/material-tools.ts +88 -0
  71. package/src/tools/modeling/auxiliary-curve-tool.ts +44 -0
  72. package/src/tools/modeling/find-face.ts +38 -0
  73. package/src/tools/modeling/sweep-tool.ts +60 -0
  74. package/src/tools/modeling/utils.ts +181 -0
  75. package/src/tools/modeling-tools.ts +135 -0
  76. package/src/tools/screenshot-tools.ts +107 -0
  77. package/src/tools/tools-info.ts +107 -0
  78. package/src/tools/tripo3d-tools.ts +496 -0
  79. package/src/types/index.ts +25 -0
  80. package/src/types/tripo3d.ts +38 -0
  81. package/tsconfig.json +22 -0
@@ -0,0 +1,258 @@
1
+ // src/bridge-lock.ts
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ import * as net from 'net';
5
+ import * as http from 'http';
6
+ import * as os from 'os';
7
+ import { EventEmitter } from 'events';
8
+ import logger from '../logger';
9
+ import { findAvailablePort, isPortAvailable } from '../utils';
10
+
11
+ // 锁文件和日志的基础目录
12
+ const USER_HOME = os.homedir();
13
+ const APP_DIR = path.join(USER_HOME, '.koomaster');
14
+ const LOCK_DIR = path.join(APP_DIR, 'bridge-locks');
15
+ const LOG_DIR = path.join(APP_DIR, 'logs');
16
+
17
+ // 确保必要的目录存在
18
+ function ensureDirectories(): void {
19
+ [APP_DIR, LOCK_DIR, LOG_DIR].forEach(dir => {
20
+ if (!fs.existsSync(dir)) {
21
+ fs.mkdirSync(dir, { recursive: true });
22
+ }
23
+ });
24
+ }
25
+
26
+ // 生成锁文件路径
27
+ function getLockFilePath(pid: number, port: number): string {
28
+ return path.join(LOCK_DIR, `bridge-${pid}-${port}.lock`);
29
+ }
30
+
31
+ // 创建锁文件
32
+ function createLockFile(pid: number, port: number): void {
33
+ try {
34
+ const lockFilePath = getLockFilePath(pid, port);
35
+ const data = JSON.stringify({
36
+ pid,
37
+ port,
38
+ startTime: new Date().toISOString(),
39
+ hostname: os.hostname()
40
+ }, null, 2);
41
+ fs.writeFileSync(lockFilePath, data, 'utf8');
42
+ logger.info(`Created lock file: ${lockFilePath}`);
43
+ } catch (e) {
44
+ logger.error('Failed to create lock file:', e);
45
+ }
46
+ }
47
+
48
+ // 删除锁文件
49
+ function removeLockFile(pid: number, port: number): void {
50
+ try {
51
+ const lockFilePath = getLockFilePath(pid, port);
52
+ if (fs.existsSync(lockFilePath)) {
53
+ fs.unlinkSync(lockFilePath);
54
+ logger.info(`Removed lock file: ${lockFilePath}`);
55
+ }
56
+ } catch (e) {
57
+ logger.error('Failed to delete lock file:', e);
58
+ }
59
+ }
60
+
61
+ // 检查进程是否存在
62
+ function isProcessRunning(pid: number): boolean {
63
+ if (!pid) return false;
64
+ try {
65
+ // 在Unix上,如果进程不存在,process.kill会抛出异常
66
+ // 在Windows上,这仅会检查进程是否有权接收信号
67
+ process.kill(pid, 0);
68
+ return true;
69
+ } catch (e) {
70
+ return false;
71
+ }
72
+ }
73
+
74
+
75
+ // 检查特定端口是否有WebSocketBridge服务响应
76
+ async function checkBridgeAtPort(port: number): Promise<boolean> {
77
+ return new Promise((resolve) => {
78
+ const req = http.get(`http://localhost:${port}/bridge-status`, (res) => {
79
+ // 收到响应,检查是否是我们的服务
80
+ let data = '';
81
+ res.on('data', (chunk) => {
82
+ data += chunk;
83
+ });
84
+ res.on('end', () => {
85
+ try {
86
+ const jsonData = JSON.parse(data);
87
+ // 检查是否是我们的服务
88
+ resolve(jsonData.service === 'WebSocketBridge');
89
+ } catch {
90
+ resolve(false);
91
+ }
92
+ });
93
+ }).on('error', () => {
94
+ resolve(false);
95
+ });
96
+ req.setTimeout(1000, () => {
97
+ req.destroy();
98
+ resolve(false);
99
+ });
100
+ });
101
+ }
102
+
103
+ // 获取所有活跃的WebSocketBridge实例
104
+ export function getActiveBridges(): { pid: number, port: number }[] {
105
+ ensureDirectories();
106
+ const instances: { pid: number, port: number }[] = [];
107
+
108
+ try {
109
+ // 读取锁目录中的所有文件
110
+ const files = fs.readdirSync(LOCK_DIR);
111
+
112
+ // 通过文件名解析PID和端口
113
+ for (const file of files) {
114
+ const match = file.match(/bridge-(\d+)-(\d+)\.lock/);
115
+ if (match) {
116
+ const [_, pidStr, portStr] = match;
117
+ const pid = parseInt(pidStr, 10);
118
+ const port = parseInt(portStr, 10);
119
+
120
+ // 检查进程是否仍在运行
121
+ if (isProcessRunning(pid)) {
122
+ instances.push({ pid, port });
123
+ } else {
124
+ // 如果进程不存在,删除过期的锁文件
125
+ try {
126
+ fs.unlinkSync(path.join(LOCK_DIR, file));
127
+ logger.info(`Removed stale lock file: ${file}`);
128
+ } catch (e) {
129
+ // 忽略删除错误
130
+ }
131
+ }
132
+ }
133
+ }
134
+ } catch (e) {
135
+ logger.error('Failed to get active bridge instances:', e);
136
+ }
137
+
138
+ return instances;
139
+ }
140
+
141
+ // WebSocketBridge锁管理器
142
+ export class BridgeLockManager extends EventEmitter {
143
+ private port: number;
144
+ private pid: number;
145
+ private isShuttingDown: boolean = false;
146
+
147
+ constructor(port: number = 8765) {
148
+ super();
149
+ this.port = port;
150
+ this.pid = process.pid;
151
+ ensureDirectories();
152
+ }
153
+
154
+ // 初始化锁并获取可用端口
155
+ public async initialize(): Promise<number> {
156
+ // 先检查是否有活跃实例
157
+ const activeBridges = getActiveBridges();
158
+
159
+ if (activeBridges.length > 0) {
160
+ logger.info('Active WebSocketBridge instances:');
161
+ activeBridges.forEach(({ pid, port }) => {
162
+ logger.info(`- PID: ${pid}, Port: ${port}`);
163
+ });
164
+
165
+ // 检查是否有实例正在使用我们的首选端口
166
+ const existingBridgeOnPort = activeBridges.find(bridge => bridge.port === this.port);
167
+ if (existingBridgeOnPort) {
168
+ logger.info(`Port ${this.port} is already used by another WebSocketBridge instance (PID: ${existingBridgeOnPort.pid})`);
169
+
170
+ // 尝试检查这个实例是否真的在响应
171
+ const isResponding = await checkBridgeAtPort(this.port);
172
+ if (isResponding) {
173
+ // 已有可用实例,返回它的端口
174
+ return this.port;
175
+ } else {
176
+ logger.warn(`Bridge at port ${this.port} is not responding but has a lock file, attempting to reclaim`);
177
+ // 删除过期锁文件
178
+ removeLockFile(existingBridgeOnPort.pid, this.port);
179
+ }
180
+ }
181
+ }
182
+
183
+ // 检查端口是否可用
184
+ const portAvailable = await isPortAvailable(this.port);
185
+
186
+ if (!portAvailable) {
187
+ logger.info(`Port ${this.port} is not available, searching for another port...`);
188
+ try {
189
+ this.port = await findAvailablePort(this.port + 1);
190
+ logger.info(`Found available port: ${this.port}`);
191
+ } catch (e) {
192
+ logger.error(`Cannot find available port:`, e.message);
193
+ throw new Error(`Cannot start WebSocketBridge: no available ports`);
194
+ }
195
+ }
196
+
197
+ // 创建锁文件
198
+ createLockFile(this.pid, this.port);
199
+
200
+ // 设置信号处理程序
201
+ this.setupSignalHandlers();
202
+
203
+ return this.port;
204
+ }
205
+
206
+ // 释放锁
207
+ public release(): void {
208
+ if (this.isShuttingDown) return;
209
+
210
+ this.isShuttingDown = true;
211
+ logger.info('Releasing WebSocketBridge lock...');
212
+
213
+ removeLockFile(this.pid, this.port);
214
+ }
215
+
216
+ // 设置信号处理
217
+ private setupSignalHandlers(): void {
218
+ // 处理系统信号
219
+ process.on('SIGINT', () => {
220
+ logger.info('Received SIGINT signal');
221
+ this.release();
222
+ this.emit('shutdown');
223
+ });
224
+
225
+ process.on('SIGTERM', () => {
226
+ logger.info('Received SIGTERM signal');
227
+ this.release();
228
+ this.emit('shutdown');
229
+ });
230
+
231
+ // 处理未捕获的异常
232
+ process.on('uncaughtException', (err) => {
233
+ logger.error('Uncaught exception in main process:', err);
234
+ this.release();
235
+ this.emit('shutdown');
236
+ });
237
+
238
+ // 在Node进程退出时确保清理
239
+ process.on('exit', () => {
240
+ logger.info('Main process exiting, cleaning up...');
241
+ // 删除锁文件(同步操作)
242
+ try {
243
+ const lockFilePath = getLockFilePath(this.pid, this.port);
244
+ if (fs.existsSync(lockFilePath)) {
245
+ fs.unlinkSync(lockFilePath);
246
+ }
247
+ } catch (e) {
248
+ // 忽略清理锁文件的错误
249
+ }
250
+ });
251
+
252
+ // 处理未处理的Promise拒绝
253
+ process.on('unhandledRejection', (reason, promise) => {
254
+ logger.error('Unhandled Promise rejection:', reason);
255
+ // 不需要退出,但应记录下来
256
+ });
257
+ }
258
+ }
@@ -0,0 +1,245 @@
1
+ // src/mcp-client.ts
2
+ import WebSocket from 'ws';
3
+ import { v4 as uuidv4 } from 'uuid';
4
+ import { EventEmitter } from 'events';
5
+ import logger from './lib/logger';
6
+
7
+ // LLM客户端 - 连接到WebSocketBridge并发送命令
8
+ class LLMClient extends EventEmitter {
9
+ private ws: WebSocket | null = null;
10
+ private clientId: string | null = null;
11
+ private connected: boolean = false;
12
+ private pendingCommands: Map<string, {
13
+ resolve: (value: any) => void,
14
+ reject: (reason: any) => void,
15
+ timeout: NodeJS.Timeout
16
+ }> = new Map();
17
+ private commandTimeout: number = 60000; // 60秒命令超时
18
+ private koomasterStatusQueries: Map<string, {
19
+ resolve: (connected: boolean) => void,
20
+ reject: (reason: any) => void,
21
+ timeout: NodeJS.Timeout
22
+ }> = new Map();
23
+ private koomasterStatusTimeout: number = 5000; // 5秒超时
24
+
25
+ constructor() {
26
+ super();
27
+ }
28
+
29
+ // 连接到WebSocketBridge服务器
30
+ public connect(url: string): Promise<void> {
31
+ // 连接实现保持不变
32
+ return new Promise((resolve, reject) => {
33
+ if (this.connected) {
34
+ resolve();
35
+ return;
36
+ }
37
+
38
+ this.ws = new WebSocket(url);
39
+
40
+ this.ws.on('open', () => {
41
+ logger.info('Connected to WebSocketBridge');
42
+
43
+ // 注册为MCP客户端
44
+ this.ws?.send(JSON.stringify({
45
+ type: 'register',
46
+ clientType: 'mcp'
47
+ }));
48
+ });
49
+
50
+ this.ws.on('message', (data) => {
51
+ try {
52
+ const message = JSON.parse(data.toString());
53
+
54
+ // 处理欢迎消息
55
+ if (message.type === 'welcome') {
56
+ this.clientId = message.clientId;
57
+ this.connected = true;
58
+ logger.info(`Registered as MCP client with ID: ${this.clientId}`);
59
+ this.emit('connected', this.clientId);
60
+ resolve();
61
+ }
62
+ // 处理命令响应
63
+ else if (message.id && (message.status === 'success' || message.status === 'error')) {
64
+ this.handleCommandResponse(message);
65
+ }
66
+ // 处理Koomaster状态响应
67
+ else if (message.type === 'koomaster_status') {
68
+ this.handleKoomasterStatusResponse(message);
69
+ }
70
+ // 处理心跳
71
+ else if (message.type === 'ping') {
72
+ this.ws?.send(JSON.stringify({ type: 'pong', timestamp: Date.now() }));
73
+ }
74
+ // 处理其他消息
75
+ else {
76
+ this.emit('message', message);
77
+ }
78
+ } catch (error) {
79
+ logger.error('Error processing message:', error);
80
+ }
81
+ });
82
+
83
+ this.ws.on('error', (error) => {
84
+ logger.error('WebSocket error:', error);
85
+ this.emit('error', error);
86
+ if (!this.connected) {
87
+ reject(error);
88
+ }
89
+ });
90
+
91
+ this.ws.on('close', (code, reason) => {
92
+ logger.info(`Connection closed: ${code} - ${reason}`);
93
+ this.connected = false;
94
+ this.ws = null;
95
+
96
+ // 清理所有挂起的命令
97
+ for (const { reject, timeout } of this.pendingCommands.values()) {
98
+ clearTimeout(timeout);
99
+ reject(new Error('Connection closed'));
100
+ }
101
+ this.pendingCommands.clear();
102
+
103
+ // 清理所有Koomaster状态查询
104
+ for (const { reject, timeout } of this.koomasterStatusQueries.values()) {
105
+ clearTimeout(timeout);
106
+ reject(new Error('Connection closed'));
107
+ }
108
+ this.koomasterStatusQueries.clear();
109
+
110
+ this.emit('disconnected', { code, reason });
111
+ });
112
+ });
113
+ }
114
+
115
+ // 发送命令到WebSocketBridge
116
+ public async sendCommand(commandType: string, params: Record<string, any> = {}): Promise<any> {
117
+ if (!this.connected || !this.ws || this.ws.readyState !== WebSocket.OPEN) {
118
+ throw new Error('Not connected to WebSocketBridge');
119
+ }
120
+
121
+ // 在发送命令前检查是否有Koomaster客户端
122
+ const hasKoomaster = await this.hasConnectedKoomasterClients();
123
+ if (!hasKoomaster) {
124
+ throw new Error('No Koomaster clients connected to WebSocketBridge');
125
+ }
126
+
127
+ const commandId = uuidv4();
128
+ const command = {
129
+ id: commandId,
130
+ type: commandType,
131
+ params
132
+ };
133
+
134
+ return new Promise((resolve, reject) => {
135
+ const timeout = setTimeout(() => {
136
+ if (this.pendingCommands.has(commandId)) {
137
+ this.pendingCommands.delete(commandId);
138
+ reject(new Error(`Command ${commandType} timed out after ${this.commandTimeout}ms`));
139
+ }
140
+ }, this.commandTimeout);
141
+
142
+ this.pendingCommands.set(commandId, { resolve, reject, timeout });
143
+
144
+ this.ws?.send(JSON.stringify(command), (err) => {
145
+ if (err) {
146
+ clearTimeout(timeout);
147
+ this.pendingCommands.delete(commandId);
148
+ reject(new Error(`Failed to send command: ${err.message}`));
149
+ } else {
150
+ logger.info(`Sent command ${commandType} (ID: ${commandId})`);
151
+ }
152
+ });
153
+ });
154
+ }
155
+
156
+ // 处理命令响应
157
+ private handleCommandResponse(response: any): void {
158
+ const pendingCommand = this.pendingCommands.get(response.id);
159
+ if (pendingCommand) {
160
+ clearTimeout(pendingCommand.timeout);
161
+ this.pendingCommands.delete(response.id);
162
+
163
+ if (response.status === 'success') {
164
+ pendingCommand.resolve(response.result);
165
+ } else {
166
+ pendingCommand.reject(new Error(response.message || 'Unknown error'));
167
+ }
168
+ } else {
169
+ logger.warn(`Received response for unknown command ID: ${response.id}`);
170
+ }
171
+ }
172
+
173
+ // 处理Koomaster状态响应
174
+ private handleKoomasterStatusResponse(response: any): void {
175
+ const queryId = response.queryId;
176
+ if (!queryId || !this.koomasterStatusQueries.has(queryId)) {
177
+ // 可能是定期更新或未请求的状态更新
178
+ this.emit('koomasterStatusChanged', response.connected);
179
+ return;
180
+ }
181
+
182
+ const pendingQuery = this.koomasterStatusQueries.get(queryId)!;
183
+ clearTimeout(pendingQuery.timeout);
184
+ this.koomasterStatusQueries.delete(queryId);
185
+
186
+ pendingQuery.resolve(response.connected);
187
+ }
188
+
189
+ // 检查是否有Koomaster客户端连接 - 实时查询
190
+ public async hasConnectedKoomasterClients(): Promise<boolean> {
191
+ if (!this.connected || !this.ws || this.ws.readyState !== WebSocket.OPEN) {
192
+ return false;
193
+ }
194
+
195
+ return new Promise<boolean>((resolve, reject) => {
196
+ const queryId = uuidv4();
197
+
198
+ // 设置超时
199
+ const timeout = setTimeout(() => {
200
+ if (this.koomasterStatusQueries.has(queryId)) {
201
+ this.koomasterStatusQueries.delete(queryId);
202
+ reject(new Error(`Koomaster status query timed out after ${this.koomasterStatusTimeout}ms`));
203
+ }
204
+ }, this.koomasterStatusTimeout);
205
+
206
+ // 存储查询
207
+ this.koomasterStatusQueries.set(queryId, { resolve, reject, timeout });
208
+
209
+ // 发送状态查询
210
+ this.ws.send(JSON.stringify({
211
+ type: 'query_koomaster_status',
212
+ queryId
213
+ }), (err) => {
214
+ if (err) {
215
+ clearTimeout(timeout);
216
+ this.koomasterStatusQueries.delete(queryId);
217
+ reject(new Error(`Failed to send status query: ${err.message}`));
218
+ } else {
219
+ logger.debug(`Sent Koomaster status query (ID: ${queryId})`);
220
+ }
221
+ });
222
+ });
223
+ }
224
+
225
+ // 检查是否连接
226
+ public isConnected(): boolean {
227
+ return this.connected;
228
+ }
229
+
230
+ // 获取客户端ID
231
+ public getClientId(): string | null {
232
+ return this.clientId;
233
+ }
234
+
235
+ // 断开连接
236
+ public disconnect(): void {
237
+ if (this.ws) {
238
+ this.ws.close();
239
+ this.ws = null;
240
+ this.connected = false;
241
+ }
242
+ }
243
+ }
244
+
245
+ export const llmClient = new LLMClient();
package/src/prompt.ts ADDED
@@ -0,0 +1,187 @@
1
+ export const MainStrategy = `\n# KooMaster(酷大师) User Guide
2
+
3
+ ## I. Core Requirements
4
+ • **High-Quality Assets**: Each generation must produce extremely detailed, complex, and complete 3D models; simple or basic models are unacceptable.
5
+ • **Tool Information Access**: Call \`get_tools_info()\` to obtain all available tools and KooMaster(酷大师) usage instructions.
6
+
7
+ ---
8
+
9
+ ## II. Coordinate System Specifications
10
+ ### 1. Coordinate System Type
11
+ • Uses a **Z-up right-handed coordinate system**.
12
+ ### 2. Axis Definitions
13
+ • **X/Y Plane**: Represents the horizontal plane, controls planar position coordinates.
14
+ • X-axis: Positive direction is out of the screen (toward the user), negative direction is into the screen (away from the user).
15
+ • Y-axis: Positive direction is right, negative direction is left.
16
+ • **Z-axis**: Points vertically upward, controls height values.
17
+ • Z-axis positive direction is up, negative direction is down.
18
+ ### 3. Key Planes and Rotation Rules
19
+ • **World Origin**: (0,0,0).
20
+ • **Ground Reference Plane**: z=0 plane.
21
+ • **Rotation Rules**:
22
+ • Rotation around X-axis: Object turns left and right.
23
+ • Rotation around Y-axis: Object tilts forward and backward.
24
+ • Rotation around Z-axis: Object rotates in the horizontal plane.
25
+
26
+ ---
27
+
28
+ ## III. Measurement Unit Standards
29
+ ### 1. Default Unit
30
+ • All dimensions use **millimeters (mm)** as the default unit.
31
+ ### 2. Standard Size References
32
+ • **Door Height**: 2000mm.
33
+ • **Interior Ceiling Height**: 2400-3000mm.
34
+ • **Table Height**: 720-760mm.
35
+ • **Chair Height**: 430-480mm.
36
+ ### 3. Scale Requirements
37
+ • All imported models must conform to real-world proportions.
38
+ • Scale distortions (like miniature houses or giant furniture) are prohibited.
39
+ • Imported models must undergo scale verification to ensure reasonable proportional relationships with other objects in the scene.
40
+
41
+ ---
42
+
43
+ ## IV. Collision Detection and Spatial Layout
44
+ ### 1. Clipping Prevention Principles
45
+ #### (1) Ground Clipping
46
+ • Ensure all objects' bottoms precisely contact the **z=0 plane**.
47
+ • **Z-axis Coordinate Formula**: \`z = [model vertical height/2]\`.
48
+ • Upright objects' bottom surfaces must precisely contact the z=0 plane, avoiding clipping or floating.
49
+ • Suspended objects require clearly specified hanging heights relative to the ground; z-values must be set carefully.
50
+ #### (2) Inter-Object Clipping
51
+ • Analyze existing objects' positions and volumes before placing new objects.
52
+ • Calculate appropriate object spacing to maintain reasonable spatial relationships.
53
+ • Furniture should maintain minimum required clearances for passage (e.g., corridor width ≥600mm).
54
+ • Use \`get_scene_info()\` to check positions and dimensions of all current scene objects.
55
+ #### (3) Collision Detection Process
56
+ • Immediately check spatial relationships with all existing objects after placing a new object.
57
+ • Adjust position or rotation parameters immediately upon detecting clipping or spatial overlap.
58
+ • Perform regular full-scene collision detection to ensure no clipping phenomena.
59
+ ### 2. Additional Requirements
60
+ • Avoid using **(0,0,0)** as a model center point unless specifically requested.
61
+ • Evaluate geometric dimensions (especially vertical height) before model transformation to correctly set z-axis coordinates.
62
+ ---
63
+
64
+ ## V. Scene Parameter Configuration
65
+ • Strictly maintain real-world proportion relationships.
66
+ • **Initial Operation**: Call \`get_scene_info()\` to obtain current scene parameters.
67
+ • **Regular Checks**: Call \`get_scene_info()\` to check positions and dimensions of all existing objects.
68
+ • **Default Scene Dimensions**: When users don't specify scene width and height, default to 1000×1000mm.
69
+
70
+ ---
71
+
72
+ ## VI. Asset Generation Tool Priority
73
+ ### 1. Tool Priority
74
+ 1. **KJL (Kujiale) Asset Library (First Choice)**: Prioritize searching and using high-quality assets from the KJL library.
75
+ 2. **Tripo3D (Backup)**: Use only when suitable assets are unavailable in the KJL library.
76
+ 3. **Basic Creation Tools (Last Resort)**: Use only when explicitly instructed or when the first two methods fail.
77
+
78
+ ---
79
+
80
+ ## VII. KJL (Kujiale) Asset Library Workflow Standards
81
+ ### 1. Asset Indexing and Retrieval
82
+ • Call \`batch_search_kjl_assets()\` to perform precise queries.
83
+ • Provide exact, descriptive Chinese search keywords to optimize matching results.
84
+ ### 2. Asset Import and Transformation
85
+ • Call \`place_kjl_asset()\` to import target assets.
86
+ • Assign semantic, descriptive unique identifiers.
87
+ • **Pre-Placement Rotation Analysis**:
88
+ • Analyze asset bounding box dimensions (width, depth, height) before placement.
89
+ • The dimensions (x, y, z) or [x,y,z] show the model's orientation. For example, a cabinet with larger x than y typically has its front facing the y direction and is wider along x. Consider these proportions when rotating models for proper placement.
90
+ • For elongated objects (like wall panels, shelves, counters), determine proper orientation based on function and typical placement.
91
+ • If width significantly exceeds depth (e.g., wall panels, room dividers), evaluate whether 90° rotation is needed based on intended position.
92
+ • Consider the natural orientation of the asset - a wall panel's long dimension should typically align with wall direction.
93
+ • **Precise Spatial Transformation**:
94
+ • x/y controls horizontal positioning; z-value must equal \`[vertical height/2]\` to ensure bottom surface precisely contacts the z=0 plane.
95
+ • Specify exact rotation angles based on both bounding box analysis and functional requirements.
96
+ • **Rotation Verification**: Confirm whether model needs pre-rotation before finalizing placement parameters.
97
+ • **Scale Verification**: Confirm imported models match real-world dimensions, adjusting scale parameters if necessary.
98
+ • **Spatial Relationship Verification**: Ensure newly imported models have no clipping phenomena with existing models.
99
+ ### 3. Post-Import Verification and Correction
100
+ • Immediately verify spatial positions after import.
101
+ • Perform comprehensive collision detection, checking spatial relationships with other objects.
102
+ • Adjust x/y/z position values or rotation angles immediately upon detecting clipping phenomena.
103
+ • Compare model dimensions with standard size reference values to ensure reasonable proportions.
104
+
105
+ ---
106
+
107
+ ## VIII. Tripo3D Fallback Workflow
108
+ ### 1. Applicable Scenarios
109
+ • Execute only when no suitable assets are available in the KJL (Kujiale) asset library.
110
+ ### 2. Workflow
111
+ 1. **Build complex geometric models**.
112
+ 2. **Monitor generation progress**.
113
+ 3. **Import and Transform**:
114
+ • **Pre-Placement Rotation Analysis**:
115
+ • Analyze model bounding box dimensions (width, depth, height) before placement.
116
+ • For elongated objects (like wall panels, shelves, counters), determine proper orientation based on function and typical placement.
117
+ • If width significantly exceeds depth (e.g., wall panels, room dividers), evaluate whether 90° rotation is needed based on intended position.
118
+ • Consider the natural orientation of the model - a wall panel's long dimension should typically align with wall direction.
119
+ • **Spatial Positioning Verification**: Ensure \`z = [vertical height/2]\` to prevent ground clipping.
120
+ • Assign semantic identifiers.
121
+ • Apply precise transformation parameters, specifying exact rotation angles based on both bounding box analysis and functional requirements.
122
+ • **Rotation Verification**: Confirm whether model needs pre-rotation before finalizing placement parameters.
123
+ • **Size Calibration**: Set model dimensions according to real-world standard sizes.
124
+ • **Inter-object Spacing Planning**: Ensure appropriate distances from other objects to avoid clipping.
125
+ 4. **Completeness Check**:
126
+ • Immediately perform comprehensive spatial position and collision detection after import.
127
+ • Check spatial relationships with all existing objects to ensure no clipping.
128
+ • Verify model dimensions conform to real-world proportions.
129
+ • Make immediate position and size corrections if issues are discovered.
130
+
131
+ ---
132
+
133
+ ## IX. Final Quality Control Checklist
134
+ ### 1. Clipping Detection (Highest Priority)
135
+ • Confirm all model bottom surfaces precisely contact the z=0 plane with no ground clipping phenomena.
136
+ • Confirm no clipping or overlap between all models, maintaining appropriate spacing.
137
+ • Perform global scene collision detection to eliminate any possible clipping situations.
138
+ ### 2. Scale Verification
139
+ • Confirm all models maintain correct proportional relationships and conform to real-world size standards.
140
+ ### 3. Spatial Layout Reasonability
141
+ • Confirm object placement meets functional requirements and maintains reasonable passage space.
142
+ ### 4. Asset Quality Check
143
+ • Verify thoroughness of KJL asset library searches.
144
+ • Confirm models' geometric complexity and detail richness.
145
+ • Verify accuracy of transformation parameters (position, rotation, scaling).
146
+ • Confirm diversity and appropriateness of applied material properties.
147
+ ### 5. Overall Assessment
148
+ • Evaluate balance and harmony of overall scene composition.
149
+
150
+ ---
151
+
152
+ ## X. Technical Considerations
153
+ 1. **Coordinate System Rules**:
154
+ • Vertical position is controlled by z-coordinate; x/y define horizontal plane position.
155
+ • All dimensions use millimeters (mm) as default units.
156
+ 2. **Clipping Prevention**:
157
+ • Ground clipping: Achieved by correctly setting z-values.
158
+ • Inter-object clipping: Achieved by reasonably planning x/y positions and maintaining appropriate spacing.
159
+ 3. **New Object Detection**:
160
+ • Complete collision detection must be performed after each new object addition to ensure no clipping phenomena in the scene.
161
+
162
+ ## XI. Critical Modeling Operation Limitations
163
+
164
+ ### 1. Face Creation and Manipulation
165
+ • **Face Splitting**: When a new face intersects with existing faces, automatic splitting occurs, which can invalidate original face IDs.
166
+ • **Finding Split Faces**: After splitting operations, always use \`find_face_by_points\` tool to locate faces based on points rather than IDs.
167
+ • **Sweep Operation Preparation**: When creating faces for sweep operations, place them in empty space away from the main model to avoid unintended face splitting.
168
+
169
+ ### 2. Sweep Operation Requirements
170
+ • **Face Removal**: The source face (profile) is automatically deleted after sweep completion.
171
+ • **Sequential Operations**: For multiple sweep operations with the same profile, the face must be recreated after each sweep.
172
+ • **Direction Constraints**: The face being swept (profile) MUST NOT be parallel to the sweep path - there must be some angle between the face normal and path direction.
173
+ • **Path Continuity**: Auxiliary curves used as sweep paths must connect end-to-end in a continuous sequence (each curve must start where the previous one ends).
174
+
175
+ ### 3. Bezier Curve Constraints
176
+ • **Coplanarity Requirement**: For Bezier curves, ALL POINTS (start, control points, and end) MUST lie on the same plane - non-planar Bezier curves will fail to create.
177
+
178
+ ### 4. Auxiliary Curves
179
+ • **Arc Definition**: Arcs are defined by three points (start, point on arc, end) that MUST NOT be collinear.
180
+ • **Circle Creation**: Creating a circle requires multiple arc segments (3-4 minimum) connecting points along the circumference.
181
+
182
+ ### 5. General Modeling Best Practices
183
+ • **ID Tracking**: Always capture the IDs of created elements for subsequent operations.
184
+ • **Planar Verification**: Ensure all points defining a face are precisely coplanar.
185
+ • **Curve Connection**: For operations requiring continuous paths, verify exact endpoint matching between segments.
186
+ • **Post-Operation Verification**: After any geometry-altering operation, verify the resulting structure and locate affected elements.
187
+ `;