@pixel-normal-edit/mcp 2.0.10 → 2.1.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/core/command-bus.js +6 -3
- package/core/server.js +98 -3
- package/package.json +1 -1
- package/rules/README.md +358 -285
- package/rules/index.js +9 -9
- package/rules/prerequisites.js +118 -61
- package/rules/rules.js +75 -34
- package/rules/workflow.js +262 -56
package/rules/index.js
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* rules/index.js — Rules Module Aggregator
|
|
4
4
|
*
|
|
5
|
-
* Aggregates
|
|
5
|
+
* Aggregates and exports all rules, workflow engine, and prerequisite tools.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
* 1. rules.js —
|
|
9
|
-
* 2. workflow.js — Workflow engine (
|
|
10
|
-
* 3. prerequisites.js — MCP Tools
|
|
7
|
+
* This module provides:
|
|
8
|
+
* 1. rules.js — Defines rules (naming, constraints, validators)
|
|
9
|
+
* 2. workflow.js — Workflow engine (manages step order)
|
|
10
|
+
* 3. prerequisites.js — MCP Tools for workflow (start, status, advance, validate)
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
* -
|
|
14
|
-
* -
|
|
12
|
+
* How to add a new rule:
|
|
13
|
+
* - Add to rules.js (NAMING_RULES, WORKFLOW_STEPS, DRAWING_CONSTRAINTS)
|
|
14
|
+
* - If complex logic is needed, create a new file in rules/ and import it here
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
const rules = require('./rules');
|
|
@@ -19,7 +19,7 @@ const workflow = require('./workflow');
|
|
|
19
19
|
const prerequisites = require('./prerequisites');
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* Register
|
|
22
|
+
* Register all workflow/prerequisite tools to the MCP server
|
|
23
23
|
* @param {McpServer} server
|
|
24
24
|
*/
|
|
25
25
|
function registerAll(server) {
|
package/rules/prerequisites.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* prerequisites.js — Prerequisites Check
|
|
3
|
+
* prerequisites.js — Prerequisites Check
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* This is an MCP Tool for the agent to call before starting to draw.
|
|
6
|
+
* It will check all prerequisites and return detailed instructions.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* IMPORTANT: The Agent MUST call this tool FIRST
|
|
9
|
+
* before performing any drawing operations.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
const { z } = require('zod');
|
|
13
|
-
const { validateCanvasName, validateCanvasSize, DRAWING_CONSTRAINTS,
|
|
13
|
+
const { validateCanvasName, validateCanvasSize, DRAWING_CONSTRAINTS, MODES, DRAWING_PHASES } = require('./rules');
|
|
14
14
|
const workflow = require('./workflow');
|
|
15
15
|
const { registerTool } = require('../core/server');
|
|
16
16
|
|
|
@@ -19,53 +19,39 @@ const { registerTool } = require('../core/server');
|
|
|
19
19
|
* @param {McpServer} server
|
|
20
20
|
*/
|
|
21
21
|
function register(server) {
|
|
22
|
-
// ── Tool 1: workflow_start — Bắt đầu workflow ─────────────────────────
|
|
23
22
|
registerTool(server, 'workflow_start',
|
|
24
|
-
`🚀
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
1. create_canvas — Tạo canvas mới
|
|
30
|
-
2. name_canvas — Đặt tên cho canvas
|
|
31
|
-
3. resize_canvas — Resize nếu cần
|
|
32
|
-
4. enable_animation — Bật animation nếu cần
|
|
33
|
-
5. setup_layers — Thiết lập layers
|
|
34
|
-
6. prepare_colors — Chuẩn bị màu sắc
|
|
35
|
-
7. draw — Vẽ (chỉ được vẽ sau các bước trên)
|
|
36
|
-
8. review — Kiểm tra kết quả
|
|
37
|
-
9. finalize — Lưu và hoàn tất`,
|
|
38
|
-
{},
|
|
39
|
-
() => {
|
|
23
|
+
`🚀 REQUIRED: Call this tool FIRST before drawing anything.
|
|
24
|
+
This tool initializes a drawing workflow with sequential steps for a specific mode.
|
|
25
|
+
Modes: CREATE_IMAGE, EDIT_IMAGE, CREATE_ANIMATION`,
|
|
26
|
+
{ mode: z.enum([MODES.CREATE_IMAGE, MODES.EDIT_IMAGE, MODES.CREATE_ANIMATION]).describe('Workflow mode to start') },
|
|
27
|
+
(p) => {
|
|
40
28
|
const session = require('../core/command-bus').SESSION;
|
|
41
|
-
const state = workflow.start(session);
|
|
29
|
+
const state = workflow.start(session, p.mode);
|
|
42
30
|
return {
|
|
43
|
-
content: [{ type: 'text', text: `🚀 **Workflow
|
|
31
|
+
content: [{ type: 'text', text: `🚀 **Workflow started in mode: ${p.mode}!**\n\n${workflow.getProgressReport(session)}\n\n---\nStart with step: **${state.steps[0].label}** → ${state.steps[0].description}` }]
|
|
44
32
|
};
|
|
45
33
|
});
|
|
46
34
|
|
|
47
|
-
// ── Tool 2: workflow_status — Xem trạng thái hiện tại ─────────────────
|
|
48
35
|
registerTool(server, 'workflow_status',
|
|
49
|
-
'
|
|
36
|
+
'View current workflow progress: current mode, layer, frame, steps and statuses.',
|
|
50
37
|
{},
|
|
51
38
|
() => {
|
|
52
39
|
const session = require('../core/command-bus').SESSION;
|
|
53
40
|
const report = workflow.getProgressReport(session);
|
|
54
41
|
const current = workflow.getCurrentStep(session);
|
|
55
42
|
if (!current) {
|
|
56
|
-
return { content: [{ type: 'text', text: '⚠️
|
|
43
|
+
return { content: [{ type: 'text', text: '⚠️ Workflow has not started. Call **workflow_start** first.' }] };
|
|
57
44
|
}
|
|
58
45
|
return {
|
|
59
46
|
content: [{
|
|
60
47
|
type: 'text',
|
|
61
|
-
text: `${report}\n\n👉
|
|
48
|
+
text: `${report}\n\n👉 **Pending:** ${current.label} — ${current.description}`
|
|
62
49
|
}]
|
|
63
50
|
};
|
|
64
51
|
});
|
|
65
52
|
|
|
66
|
-
// ── Tool 3: workflow_advance — Hoàn thành bước hiện tại ───────────────
|
|
67
53
|
registerTool(server, 'workflow_advance',
|
|
68
|
-
'✅
|
|
54
|
+
'✅ Mark current step as complete and move to the next step. Only call AFTER successfully finishing the current step.',
|
|
69
55
|
{},
|
|
70
56
|
() => {
|
|
71
57
|
const session = require('../core/command-bus').SESSION;
|
|
@@ -79,66 +65,137 @@ Các bước workflow:
|
|
|
79
65
|
return { content: [{ type: 'text', text: result.message }] };
|
|
80
66
|
});
|
|
81
67
|
|
|
82
|
-
// ── Tool 4: workflow_validate — Kiểm tra trước khi gọi tool ──────────
|
|
83
68
|
registerTool(server, 'workflow_validate',
|
|
84
|
-
`🔍
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
Các stepId hợp lệ:
|
|
88
|
-
- create_canvas
|
|
89
|
-
- name_canvas
|
|
90
|
-
- resize_canvas
|
|
91
|
-
- enable_animation
|
|
92
|
-
- setup_layers
|
|
93
|
-
- prepare_colors
|
|
94
|
-
- draw
|
|
95
|
-
- review
|
|
96
|
-
- finalize`,
|
|
97
|
-
{ stepId: z.string().describe('ID của bước muốn kiểm tra (vd: "draw", "resize_canvas")') },
|
|
69
|
+
`🔍 Check if the agent is allowed to perform a certain action.
|
|
70
|
+
Call this tool BEFORE performing operations to ensure correct workflow order.`,
|
|
71
|
+
{ stepId: z.string().describe('ID of the step to validate (e.g., "INITIALIZE_CANVAS")') },
|
|
98
72
|
(p) => {
|
|
99
73
|
const session = require('../core/command-bus').SESSION;
|
|
100
74
|
const result = workflow.validateStep(session, p.stepId);
|
|
101
75
|
if (!result.allowed) {
|
|
102
76
|
return { isError: true, content: [{ type: 'text', text: result.message }] };
|
|
103
77
|
}
|
|
104
|
-
return { content: [{ type: 'text', text: result.message || `✅
|
|
78
|
+
return { content: [{ type: 'text', text: result.message || `✅ You can perform "${p.stepId}". Please proceed!` }] };
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
registerTool(server, 'workflow_set_layer',
|
|
82
|
+
'Set the active layer for the workflow tracking.',
|
|
83
|
+
{ layer: z.number().int().describe('The layer index') },
|
|
84
|
+
(p) => {
|
|
85
|
+
const session = require('../core/command-bus').SESSION;
|
|
86
|
+
const success = workflow.setLayerAndFrame(session, p.layer, undefined);
|
|
87
|
+
if (!success) {
|
|
88
|
+
return { isError: true, content: [{ type: 'text', text: '❌ Workflow not started' }] };
|
|
89
|
+
}
|
|
90
|
+
return { content: [{ type: 'text', text: `✅ Active layer set to ${p.layer}` }] };
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
registerTool(server, 'workflow_set_frame',
|
|
94
|
+
'Set the active frame for the workflow tracking (useful for animation mode).',
|
|
95
|
+
{ frame: z.number().int().describe('The frame index') },
|
|
96
|
+
(p) => {
|
|
97
|
+
const session = require('../core/command-bus').SESSION;
|
|
98
|
+
const success = workflow.setLayerAndFrame(session, undefined, p.frame);
|
|
99
|
+
if (!success) {
|
|
100
|
+
return { isError: true, content: [{ type: 'text', text: '❌ Workflow not started' }] };
|
|
101
|
+
}
|
|
102
|
+
return { content: [{ type: 'text', text: `✅ Active frame set to ${p.frame}` }] };
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
registerTool(server, 'workflow_set_phase',
|
|
106
|
+
'Set the active drawing phase (e.g. PHASE_0_SKETCH_BLOCKING, PHASE_1_BACKGROUND, etc.).',
|
|
107
|
+
{ phase: z.enum(DRAWING_PHASES).describe('The drawing phase') },
|
|
108
|
+
(p) => {
|
|
109
|
+
const session = require('../core/command-bus').SESSION;
|
|
110
|
+
const success = workflow.setPhase(session, p.phase);
|
|
111
|
+
if (!success) {
|
|
112
|
+
return { isError: true, content: [{ type: 'text', text: '❌ Workflow not started' }] };
|
|
113
|
+
}
|
|
114
|
+
return { content: [{ type: 'text', text: `✅ Active phase set to ${p.phase}` }] };
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
registerTool(server, 'workflow_setup_animation',
|
|
118
|
+
'Declare animation metadata for tracking (fps, total_frames, loop).',
|
|
119
|
+
{
|
|
120
|
+
fps: z.number().int().optional().describe('Frames per second'),
|
|
121
|
+
total_frames: z.number().int().optional().describe('Total frames in the animation'),
|
|
122
|
+
loop: z.boolean().optional().describe('Whether the animation loops')
|
|
123
|
+
},
|
|
124
|
+
(p) => {
|
|
125
|
+
const session = require('../core/command-bus').SESSION;
|
|
126
|
+
const success = workflow.setAnimationMeta(session, p.fps, p.total_frames, p.loop);
|
|
127
|
+
if (!success) {
|
|
128
|
+
return { isError: true, content: [{ type: 'text', text: '❌ Workflow not started' }] };
|
|
129
|
+
}
|
|
130
|
+
return { content: [{ type: 'text', text: `✅ Animation meta updated: FPS=${p.fps}, Frames=${p.total_frames}, Loop=${p.loop}` }] };
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
registerTool(server, 'workflow_create_input_request',
|
|
134
|
+
'Pause the workflow and ask the user for specific input via the UI (e.g. CANVAS_SIZE, APPROVE_PLAN, SELECT_EDIT_REGION).',
|
|
135
|
+
{
|
|
136
|
+
type: z.enum(['CANVAS_SIZE', 'APPROVE_PLAN', 'REVIEW_RESULT', 'SELECT_EDIT_REGION', 'ANIMATION_SETUP']).describe('The type of request'),
|
|
137
|
+
fields: z.record(z.any()).optional().describe('Context or fields for the request')
|
|
138
|
+
},
|
|
139
|
+
async (p) => {
|
|
140
|
+
const { sendCommand, SESSION } = require('../core/command-bus');
|
|
141
|
+
const reqId = workflow.createInputRequest(SESSION, p.type, p.fields || {});
|
|
142
|
+
if (!reqId) {
|
|
143
|
+
return { isError: true, content: [{ type: 'text', text: '❌ Workflow not started' }] };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const res = await sendCommand({ action: 'showUserInputRequest', type: p.type, fields: p.fields || {}, reqId }, 35000);
|
|
147
|
+
|
|
148
|
+
if (!res.isError) {
|
|
149
|
+
workflow.completeInputRequest(SESSION, reqId, res.content[0].text);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return res;
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
registerTool(server, 'workflow_require_approval',
|
|
156
|
+
'Pause the workflow and require user approval before continuing.',
|
|
157
|
+
{ required: z.boolean().describe('True to pause and wait for user, False to resume') },
|
|
158
|
+
(p) => {
|
|
159
|
+
const session = require('../core/command-bus').SESSION;
|
|
160
|
+
const success = workflow.setApprovalRequired(session, p.required);
|
|
161
|
+
if (!success) {
|
|
162
|
+
return { isError: true, content: [{ type: 'text', text: '❌ Workflow not started' }] };
|
|
163
|
+
}
|
|
164
|
+
return { content: [{ type: 'text', text: p.required ? '✅ Workflow paused, waiting for user approval.' : '✅ Workflow resumed.' }] };
|
|
105
165
|
});
|
|
106
166
|
|
|
107
|
-
// ── Tool 5: workflow_reset — Làm lại từ đầu ──────────────────────────
|
|
108
167
|
registerTool(server, 'workflow_reset',
|
|
109
|
-
'🔄 Reset workflow
|
|
168
|
+
'🔄 Reset workflow to initial state. Clears all progress.',
|
|
110
169
|
{},
|
|
111
170
|
() => {
|
|
112
171
|
const session = require('../core/command-bus').SESSION;
|
|
113
172
|
workflow.reset(session);
|
|
114
|
-
return { content: [{ type: 'text', text: '🔄 Workflow
|
|
173
|
+
return { content: [{ type: 'text', text: '🔄 Workflow reset. Please start from the beginning.' }] };
|
|
115
174
|
});
|
|
116
175
|
|
|
117
|
-
// ── Tool 6: validate_canvas_name — Kiểm tra tên canvas ───────────────
|
|
118
176
|
registerTool(server, 'validate_canvas_name',
|
|
119
|
-
`
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
{ name: z.string().describe('
|
|
177
|
+
`Validate canvas name before setting it.
|
|
178
|
+
Rules: 3-64 characters, letters, numbers, _, -, and spaces only.
|
|
179
|
+
Example: "Painting_1", "My Canvas 2024"`,
|
|
180
|
+
{ name: z.string().describe('Canvas name to validate') },
|
|
123
181
|
(p) => {
|
|
124
182
|
const result = validateCanvasName(p.name);
|
|
125
183
|
if (!result.valid) {
|
|
126
184
|
return { isError: true, content: [{ type: 'text', text: `❌ ${result.message}` }] };
|
|
127
185
|
}
|
|
128
|
-
return { content: [{ type: 'text', text: `✅
|
|
186
|
+
return { content: [{ type: 'text', text: `✅ Name "${p.name}" is valid!` }] };
|
|
129
187
|
});
|
|
130
188
|
|
|
131
|
-
// ── Tool 7: validate_canvas_size — Kiểm tra kích thước canvas ────────
|
|
132
189
|
registerTool(server, 'validate_canvas_size',
|
|
133
|
-
`
|
|
134
|
-
|
|
135
|
-
{ width: z.number().int().describe('
|
|
190
|
+
`Validate if canvas size is within allowed limits.
|
|
191
|
+
Limits: ${DRAWING_CONSTRAINTS.minCanvasSize.width}x${DRAWING_CONSTRAINTS.minCanvasSize.height} to ${DRAWING_CONSTRAINTS.maxCanvasSize.width}x${DRAWING_CONSTRAINTS.maxCanvasSize.height}`,
|
|
192
|
+
{ width: z.number().int().describe('Width'), height: z.number().int().describe('Height') },
|
|
136
193
|
(p) => {
|
|
137
194
|
const result = validateCanvasSize(p.width, p.height);
|
|
138
195
|
if (!result.valid) {
|
|
139
196
|
return { isError: true, content: [{ type: 'text', text: `❌ ${result.message}` }] };
|
|
140
197
|
}
|
|
141
|
-
return { content: [{ type: 'text', text: `✅
|
|
198
|
+
return { content: [{ type: 'text', text: `✅ Size ${p.width}x${p.height} is valid!` }] };
|
|
142
199
|
});
|
|
143
200
|
}
|
|
144
201
|
|
package/rules/rules.js
CHANGED
|
@@ -2,66 +2,103 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* rules.js — Core Drawing Rules & Constraints
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* Agent
|
|
7
|
-
*
|
|
8
|
-
* Các rules được chia làm 3 loại:
|
|
9
|
-
* 1. naming — Quy tắc đặt tên tab/canvas
|
|
10
|
-
* 2. workflow — Quy tắc thứ tự các bước
|
|
11
|
-
* 3. drawing — Quy tắc về vẽ (kích thước, màu sắc, v.v.)
|
|
5
|
+
* IMPORTANT: Every function in here is a STRICT rule.
|
|
6
|
+
* The Agent MUST NOT skip or execute them out of order.
|
|
12
7
|
*/
|
|
13
8
|
|
|
14
|
-
// ── Loại 1: Naming Rules ────────────────────────────────────────────────────
|
|
15
9
|
const NAMING_RULES = {
|
|
16
10
|
canvasTab: {
|
|
17
11
|
pattern: /^[A-Za-z0-9_\-\sÀ-ỹ]{3,64}$/,
|
|
18
|
-
message: '
|
|
19
|
-
example: '
|
|
12
|
+
message: 'Canvas name must be 3-64 characters long, containing only letters, numbers, _, -, and spaces',
|
|
13
|
+
example: 'Painting_1',
|
|
20
14
|
},
|
|
21
15
|
stamp: {
|
|
22
16
|
pattern: /^[a-z][a-z0-9_]{2,32}$/,
|
|
23
|
-
message: '
|
|
17
|
+
message: 'Stamp name must start with a lowercase letter, 3-32 characters long, containing only a-z, 0-9, _',
|
|
24
18
|
example: 'my_tree_01',
|
|
25
19
|
},
|
|
26
20
|
anchor: {
|
|
27
21
|
pattern: /^[a-z][a-z0-9_]{2,32}$/,
|
|
28
|
-
message: '
|
|
22
|
+
message: 'Anchor name must start with a lowercase letter, 3-32 characters long',
|
|
29
23
|
example: 'head_top',
|
|
30
24
|
},
|
|
31
25
|
};
|
|
32
26
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
27
|
+
const MODES = {
|
|
28
|
+
CREATE_IMAGE: 'CREATE_IMAGE',
|
|
29
|
+
EDIT_IMAGE: 'EDIT_IMAGE',
|
|
30
|
+
CREATE_ANIMATION: 'CREATE_ANIMATION'
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const STATUSES = {
|
|
34
|
+
PENDING: 'PENDING',
|
|
35
|
+
IN_PROGRESS: 'IN_PROGRESS',
|
|
36
|
+
WAITING_FOR_USER: 'WAITING_FOR_USER',
|
|
37
|
+
COMPLETED: 'COMPLETED',
|
|
38
|
+
FAILED: 'FAILED',
|
|
39
|
+
CANCELLED: 'CANCELLED'
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const DRAWING_PHASES = [
|
|
43
|
+
'PHASE_0_SKETCH_BLOCKING',
|
|
44
|
+
'PHASE_1_BACKGROUND',
|
|
45
|
+
'PHASE_2_MAIN_SHAPES',
|
|
46
|
+
'PHASE_3_LINE_SILHOUETTE',
|
|
47
|
+
'PHASE_4_BASE_COLORS',
|
|
48
|
+
'PHASE_5_SHADING',
|
|
49
|
+
'PHASE_6_LIGHTING',
|
|
50
|
+
'PHASE_7_DETAILS',
|
|
51
|
+
'PHASE_8_FINAL_REVIEW'
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
// Workflow Steps are now categorized by MODE
|
|
55
|
+
const WORKFLOW_STEPS = {
|
|
56
|
+
CREATE_IMAGE: [
|
|
57
|
+
{ id: 'INITIALIZE_CANVAS', label: 'Khởi tạo Canvas', description: 'Kiểm tra và khởi tạo kích thước canvas' },
|
|
58
|
+
{ id: 'ANALYZE_REQUEST', label: 'Phân tích yêu cầu', description: 'Phân tích yêu cầu của người dùng thành các thành phần có cấu trúc' },
|
|
59
|
+
{ id: 'PLAN_DRAWING', label: 'Lập kế hoạch vẽ', description: 'Tạo kế hoạch vẽ theo thứ tự từ tổng thể đến chi tiết (cần user xác nhận)' },
|
|
60
|
+
{ id: 'EXECUTE_PHASES', label: 'Thực hiện vẽ theo giai đoạn', description: 'Vẽ theo từng giai đoạn (PHASE_0 -> PHASE_8)' },
|
|
61
|
+
{ id: 'FINALIZE', label: 'Hoàn thiện', description: 'Lưu và hoàn tất ảnh' }
|
|
62
|
+
],
|
|
63
|
+
EDIT_IMAGE: [
|
|
64
|
+
{ id: 'ANALYZE_REQUEST', label: 'Nhận yêu cầu sửa', description: 'Phân tích chính xác nội dung cần sửa' },
|
|
65
|
+
{ id: 'GET_CURRENT_IMAGE', label: 'Lấy ảnh hiện tại', description: 'Lấy ảnh hiện tại làm nguồn gốc' },
|
|
66
|
+
{ id: 'COMPARE_AND_LOCATE', label: 'So sánh và xác định', description: 'Xác định vùng hoặc layer cần chỉnh sửa' },
|
|
67
|
+
{ id: 'EDIT_TARGET_AREA', label: 'Thực hiện chỉnh sửa', description: 'Chỉ sửa phần được yêu cầu trong phạm vi khoanh vùng' },
|
|
68
|
+
{ id: 'CHECK_HARMONY', label: 'Kiểm tra sự tương thích', description: 'Kiểm tra sự hòa hợp với các vùng xung quanh và điều chỉnh phần chuyển tiếp' },
|
|
69
|
+
{ id: 'FINALIZE', label: 'Cập nhật thay đổi', description: 'Cập nhật thay đổi vào ảnh hiện tại và kiểm tra kết quả' }
|
|
70
|
+
],
|
|
71
|
+
CREATE_ANIMATION: [
|
|
72
|
+
{ id: 'INITIALIZE_CANVAS_AND_ANIMATION', label: 'Khởi tạo Canvas và Animation', description: 'Xác định kích thước, fps, total_frames, loop' },
|
|
73
|
+
{ id: 'ANALYZE_ANIMATION', label: 'Phân tích animation', description: 'Phân tích đối tượng, chuyển động, keyframe, layer...' },
|
|
74
|
+
{ id: 'PROCESS_FRAMES', label: 'Tạo và xử lý từng frame', description: 'Xử lý từng frame theo đúng thứ tự (0 -> n)' },
|
|
75
|
+
{ id: 'CHECK_CONTINUITY', label: 'Kiểm tra tính liên tục', description: 'Kiểm tra tính liên tục của animation giữa các frame' },
|
|
76
|
+
{ id: 'FINALIZE', label: 'Hoàn thiện', description: 'Lưu và hoàn tất animation' }
|
|
77
|
+
]
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const DRAWING_STEPS = [
|
|
81
|
+
'EXECUTE_PHASES',
|
|
82
|
+
'EDIT_TARGET_AREA',
|
|
83
|
+
'PROCESS_FRAMES'
|
|
44
84
|
];
|
|
45
85
|
|
|
46
|
-
// ── Loại 3: Drawing Constraints ─────────────────────────────────────────────
|
|
47
86
|
const DRAWING_CONSTRAINTS = {
|
|
48
87
|
maxCanvasSize: { width: 1024, height: 1024 },
|
|
49
88
|
minCanvasSize: { width: 8, height: 8 },
|
|
50
|
-
allowedColors: null,
|
|
89
|
+
allowedColors: null,
|
|
51
90
|
maxStampNameLength: 32,
|
|
52
91
|
maxAnchorNameLength: 32,
|
|
53
92
|
};
|
|
54
93
|
|
|
55
|
-
// ── Validator Functions ──────────────────────────────────────────────────────
|
|
56
|
-
|
|
57
94
|
/**
|
|
58
|
-
*
|
|
95
|
+
* Validate if the canvas name is valid
|
|
59
96
|
* @param {string} name
|
|
60
97
|
* @returns {{ valid: boolean, message?: string }}
|
|
61
98
|
*/
|
|
62
99
|
function validateCanvasName(name) {
|
|
63
100
|
if (!name || typeof name !== 'string') {
|
|
64
|
-
return { valid: false, message: '
|
|
101
|
+
return { valid: false, message: 'Canvas name cannot be empty' };
|
|
65
102
|
}
|
|
66
103
|
if (!NAMING_RULES.canvasTab.pattern.test(name)) {
|
|
67
104
|
return { valid: false, message: NAMING_RULES.canvasTab.message };
|
|
@@ -70,13 +107,13 @@ function validateCanvasName(name) {
|
|
|
70
107
|
}
|
|
71
108
|
|
|
72
109
|
/**
|
|
73
|
-
*
|
|
110
|
+
* Validate if the stamp name is valid
|
|
74
111
|
* @param {string} name
|
|
75
112
|
* @returns {{ valid: boolean, message?: string }}
|
|
76
113
|
*/
|
|
77
114
|
function validateStampName(name) {
|
|
78
115
|
if (!name || typeof name !== 'string') {
|
|
79
|
-
return { valid: false, message: '
|
|
116
|
+
return { valid: false, message: 'Stamp name cannot be empty' };
|
|
80
117
|
}
|
|
81
118
|
if (!NAMING_RULES.stamp.pattern.test(name)) {
|
|
82
119
|
return { valid: false, message: NAMING_RULES.stamp.message };
|
|
@@ -85,7 +122,7 @@ function validateStampName(name) {
|
|
|
85
122
|
}
|
|
86
123
|
|
|
87
124
|
/**
|
|
88
|
-
*
|
|
125
|
+
* Validate if the canvas size is within limits
|
|
89
126
|
* @param {number} w
|
|
90
127
|
* @param {number} h
|
|
91
128
|
* @returns {{ valid: boolean, message?: string }}
|
|
@@ -93,16 +130,20 @@ function validateStampName(name) {
|
|
|
93
130
|
function validateCanvasSize(w, h) {
|
|
94
131
|
const { minCanvasSize, maxCanvasSize } = DRAWING_CONSTRAINTS;
|
|
95
132
|
if (w < minCanvasSize.width || h < minCanvasSize.height) {
|
|
96
|
-
return { valid: false, message: `
|
|
133
|
+
return { valid: false, message: `Minimum canvas size is ${minCanvasSize.width}x${minCanvasSize.height}` };
|
|
97
134
|
}
|
|
98
135
|
if (w > maxCanvasSize.width || h > maxCanvasSize.height) {
|
|
99
|
-
return { valid: false, message: `
|
|
136
|
+
return { valid: false, message: `Maximum canvas size is ${maxCanvasSize.width}x${maxCanvasSize.height}` };
|
|
100
137
|
}
|
|
101
138
|
return { valid: true };
|
|
102
139
|
}
|
|
103
140
|
|
|
104
141
|
module.exports = {
|
|
105
142
|
NAMING_RULES,
|
|
143
|
+
MODES,
|
|
144
|
+
STATUSES,
|
|
145
|
+
DRAWING_PHASES,
|
|
146
|
+
DRAWING_STEPS,
|
|
106
147
|
WORKFLOW_STEPS,
|
|
107
148
|
DRAWING_CONSTRAINTS,
|
|
108
149
|
validateCanvasName,
|