@hybridlabor-api/aos 4.0.2 → 4.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/.claude/agents/database-reviewer.md +109 -0
- package/.claude/agents/go-build-resolver.md +112 -0
- package/.claude/agents/opensource-forker.md +216 -0
- package/.claude/agents/opensource-sanitizer.md +206 -0
- package/.claude/agents/security-reviewer.md +126 -0
- package/.claude/agents/silent-failure-hunter.md +68 -0
- package/CLAUDE.md +15 -0
- package/README.md +0 -13
- package/THIRD_PARTY_NOTICES.md +133 -0
- package/package.json +4 -2
- package/skills/basic/bdbmediastorm/SKILL.md +7 -1
- package/skills/basic/startcycle/SKILL.md +2 -0
- package/skills/bdbrainstorm/SKILL.md +1 -0
- package/skills/global_config/plan-canvas/SKILL.md +233 -0
- package/skills/global_config/plan-canvas/scripts/lib/loopback-guard.js +59 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/markdown.js +301 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/sdk.js +239 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/server.js +636 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/sessions.js +271 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/ui.js +630 -0
- package/skills/global_config/plan-canvas/scripts/plan-canvas.js +419 -0
- package/.agents/skills/firecrawl/SKILL.md +0 -149
- package/.agents/skills/firecrawl/rules/install.md +0 -82
- package/.agents/skills/firecrawl/rules/security.md +0 -26
- package/.agents/skills/firecrawl-agent/SKILL.md +0 -58
- package/.agents/skills/firecrawl-build/SKILL.md +0 -39
- package/.agents/skills/firecrawl-build-interact/SKILL.md +0 -68
- package/.agents/skills/firecrawl-build-onboarding/SKILL.md +0 -103
- package/.agents/skills/firecrawl-build-onboarding/references/auth-flow.md +0 -39
- package/.agents/skills/firecrawl-build-onboarding/references/project-setup.md +0 -20
- package/.agents/skills/firecrawl-build-onboarding/references/sdk-installation.md +0 -17
- package/.agents/skills/firecrawl-build-scrape/SKILL.md +0 -69
- package/.agents/skills/firecrawl-build-search/SKILL.md +0 -69
- package/.agents/skills/firecrawl-crawl/SKILL.md +0 -59
- package/.agents/skills/firecrawl-download/SKILL.md +0 -70
- package/.agents/skills/firecrawl-interact/SKILL.md +0 -84
- package/.agents/skills/firecrawl-map/SKILL.md +0 -51
- package/.agents/skills/firecrawl-scrape/SKILL.md +0 -69
- package/.agents/skills/firecrawl-search/SKILL.md +0 -60
- package/docs/sessions/AUDIT-HANDOVER-2026-08-28.md +0 -169
- package/docs/sessions/BDB_REMOTEOS_MCP_HANDOVER.md +0 -130
- package/docs/sessions/SESSION-HANDOVER-v3.13.md +0 -249
- package/mcps/RhinoMCP/cc-plugin/.claude/settings.json +0 -10
- package/mcps/after-effects-mcp/build/index.js +0 -840
- package/mcps/after-effects-mcp/build/scripts/applyEffect.jsx +0 -153
- package/mcps/after-effects-mcp/build/scripts/applyEffectTemplate.jsx +0 -218
- package/mcps/after-effects-mcp/build/scripts/createComposition.jsx +0 -71
- package/mcps/after-effects-mcp/build/scripts/createShapeLayer.jsx +0 -147
- package/mcps/after-effects-mcp/build/scripts/createSolidLayer.jsx +0 -114
- package/mcps/after-effects-mcp/build/scripts/createTextLayer.jsx +0 -115
- package/mcps/after-effects-mcp/build/scripts/getLayerInfo.jsx +0 -192
- package/mcps/after-effects-mcp/build/scripts/getProjectInfo.jsx +0 -90
- package/mcps/after-effects-mcp/build/scripts/listCompositions.jsx +0 -50
- package/mcps/after-effects-mcp/build/scripts/mcp-bridge-auto.jsx +0 -1773
- package/mcps/after-effects-mcp/build/scripts/setLayerProperties.jsx +0 -160
- package/mcps/bdb-remoteos-mcp/queue.db +0 -0
- package/mcps/bdb-remoteos-mcp/src/bdb_remoteos_mcp/__pycache__/__init__.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/src/bdb_remoteos_mcp/__pycache__/incus_client.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/src/bdb_remoteos_mcp/__pycache__/main.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/src/bdb_remoteos_mcp/__pycache__/queue.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/src/bdb_remoteos_mcp/__pycache__/schemas.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/src/bdb_remoteos_mcp/__pycache__/server.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/src/bdb_remoteos_mcp/__pycache__/webhook.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/tests/__pycache__/__init__.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/tests/__pycache__/mock_incus.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/tests/__pycache__/test_mcp_server.cpython-312-pytest-9.1.1.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/tests/__pycache__/test_security_redteam.cpython-312-pytest-9.1.1.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/tests/__pycache__/test_webhook.cpython-312-pytest-9.1.1.pyc +0 -0
- package/mcps/computer-use-mcp/dist/client.d.ts +0 -150
- package/mcps/computer-use-mcp/dist/client.js +0 -136
- package/mcps/computer-use-mcp/dist/entrypoint.d.ts +0 -16
- package/mcps/computer-use-mcp/dist/entrypoint.js +0 -26
- package/mcps/computer-use-mcp/dist/native.d.ts +0 -212
- package/mcps/computer-use-mcp/dist/native.js +0 -50
- package/mcps/computer-use-mcp/dist/server.d.ts +0 -32
- package/mcps/computer-use-mcp/dist/server.js +0 -342
- package/mcps/computer-use-mcp/dist/session.d.ts +0 -101
- package/mcps/computer-use-mcp/dist/session.js +0 -2372
- package/skills/bdbsaastraining/scripts/__pycache__/build_profile.cpython-314.pyc +0 -0
|
@@ -1,1773 +0,0 @@
|
|
|
1
|
-
// mcp-bridge-auto.jsx
|
|
2
|
-
// Auto-running MCP Bridge panel for After Effects
|
|
3
|
-
|
|
4
|
-
// Remove #include directives as we define functions below
|
|
5
|
-
/*
|
|
6
|
-
#include "createComposition.jsx"
|
|
7
|
-
#include "createTextLayer.jsx"
|
|
8
|
-
#include "createShapeLayer.jsx"
|
|
9
|
-
#include "createSolidLayer.jsx"
|
|
10
|
-
#include "setLayerProperties.jsx"
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
// --- Function Definitions ---
|
|
14
|
-
|
|
15
|
-
// --- createComposition (from createComposition.jsx) ---
|
|
16
|
-
function createComposition(args) {
|
|
17
|
-
try {
|
|
18
|
-
var name = args.name || "New Composition";
|
|
19
|
-
var width = parseInt(args.width) || 1920;
|
|
20
|
-
var height = parseInt(args.height) || 1080;
|
|
21
|
-
var pixelAspect = parseFloat(args.pixelAspect) || 1.0;
|
|
22
|
-
var duration = parseFloat(args.duration) || 10.0;
|
|
23
|
-
var frameRate = parseFloat(args.frameRate) || 30.0;
|
|
24
|
-
var bgColor = args.backgroundColor ? [args.backgroundColor.r/255, args.backgroundColor.g/255, args.backgroundColor.b/255] : [0, 0, 0];
|
|
25
|
-
var newComp = app.project.items.addComp(name, width, height, pixelAspect, duration, frameRate);
|
|
26
|
-
if (args.backgroundColor) {
|
|
27
|
-
newComp.bgColor = bgColor;
|
|
28
|
-
}
|
|
29
|
-
return JSON.stringify({
|
|
30
|
-
status: "success", message: "Composition created successfully",
|
|
31
|
-
composition: { name: newComp.name, id: newComp.id, width: newComp.width, height: newComp.height, pixelAspect: newComp.pixelAspect, duration: newComp.duration, frameRate: newComp.frameRate, bgColor: newComp.bgColor }
|
|
32
|
-
}, null, 2);
|
|
33
|
-
} catch (error) {
|
|
34
|
-
return JSON.stringify({ status: "error", message: error.toString() }, null, 2);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// --- createTextLayer (from createTextLayer.jsx) ---
|
|
39
|
-
function createTextLayer(args) {
|
|
40
|
-
try {
|
|
41
|
-
var compName = args.compName || "";
|
|
42
|
-
var text = args.text || "Text Layer";
|
|
43
|
-
var position = args.position || [960, 540];
|
|
44
|
-
var fontSize = args.fontSize || 72;
|
|
45
|
-
var color = args.color || [1, 1, 1];
|
|
46
|
-
var startTime = args.startTime || 0;
|
|
47
|
-
var duration = args.duration || 5;
|
|
48
|
-
var fontFamily = args.fontFamily || "Arial";
|
|
49
|
-
var alignment = args.alignment || "center";
|
|
50
|
-
var comp = null;
|
|
51
|
-
for (var i = 1; i <= app.project.numItems; i++) {
|
|
52
|
-
var item = app.project.item(i);
|
|
53
|
-
if (item instanceof CompItem && item.name === compName) { comp = item; break; }
|
|
54
|
-
}
|
|
55
|
-
if (!comp) {
|
|
56
|
-
if (app.project.activeItem instanceof CompItem) { comp = app.project.activeItem; }
|
|
57
|
-
else { throw new Error("No composition found with name '" + compName + "' and no active composition"); }
|
|
58
|
-
}
|
|
59
|
-
var textLayer = comp.layers.addText(text);
|
|
60
|
-
var textProp = textLayer.property("ADBE Text Properties").property("ADBE Text Document");
|
|
61
|
-
var textDocument = textProp.value;
|
|
62
|
-
textDocument.fontSize = fontSize;
|
|
63
|
-
textDocument.fillColor = color;
|
|
64
|
-
textDocument.font = fontFamily;
|
|
65
|
-
if (alignment === "left") { textDocument.justification = ParagraphJustification.LEFT_JUSTIFY; }
|
|
66
|
-
else if (alignment === "center") { textDocument.justification = ParagraphJustification.CENTER_JUSTIFY; }
|
|
67
|
-
else if (alignment === "right") { textDocument.justification = ParagraphJustification.RIGHT_JUSTIFY; }
|
|
68
|
-
textProp.setValue(textDocument);
|
|
69
|
-
textLayer.property("Position").setValue(position);
|
|
70
|
-
textLayer.startTime = startTime;
|
|
71
|
-
if (duration > 0) { textLayer.outPoint = startTime + duration; }
|
|
72
|
-
return JSON.stringify({
|
|
73
|
-
status: "success", message: "Text layer created successfully",
|
|
74
|
-
layer: { name: textLayer.name, index: textLayer.index, type: "text", inPoint: textLayer.inPoint, outPoint: textLayer.outPoint, position: textLayer.property("Position").value }
|
|
75
|
-
}, null, 2);
|
|
76
|
-
} catch (error) {
|
|
77
|
-
return JSON.stringify({ status: "error", message: error.toString() }, null, 2);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// --- createShapeLayer (from createShapeLayer.jsx) ---
|
|
82
|
-
function createShapeLayer(args) {
|
|
83
|
-
try {
|
|
84
|
-
var compName = args.compName || "";
|
|
85
|
-
var shapeType = args.shapeType || "rectangle";
|
|
86
|
-
var position = args.position || [960, 540];
|
|
87
|
-
var size = args.size || [200, 200];
|
|
88
|
-
var fillColor = args.fillColor || [1, 0, 0];
|
|
89
|
-
var strokeColor = args.strokeColor || [0, 0, 0];
|
|
90
|
-
var strokeWidth = args.strokeWidth || 0;
|
|
91
|
-
var startTime = args.startTime || 0;
|
|
92
|
-
var duration = args.duration || 5;
|
|
93
|
-
var name = args.name || "Shape Layer";
|
|
94
|
-
var points = args.points || 5;
|
|
95
|
-
var comp = null;
|
|
96
|
-
for (var i = 1; i <= app.project.numItems; i++) {
|
|
97
|
-
var item = app.project.item(i);
|
|
98
|
-
if (item instanceof CompItem && item.name === compName) { comp = item; break; }
|
|
99
|
-
}
|
|
100
|
-
if (!comp) {
|
|
101
|
-
if (app.project.activeItem instanceof CompItem) { comp = app.project.activeItem; }
|
|
102
|
-
else { throw new Error("No composition found with name '" + compName + "' and no active composition"); }
|
|
103
|
-
}
|
|
104
|
-
var shapeLayer = comp.layers.addShape();
|
|
105
|
-
shapeLayer.name = name;
|
|
106
|
-
var contents = shapeLayer.property("Contents");
|
|
107
|
-
var shapeGroup = contents.addProperty("ADBE Vector Group");
|
|
108
|
-
var groupContents = shapeGroup.property("Contents");
|
|
109
|
-
var shapePathProperty;
|
|
110
|
-
if (shapeType === "rectangle") {
|
|
111
|
-
shapePathProperty = groupContents.addProperty("ADBE Vector Shape - Rect");
|
|
112
|
-
shapePathProperty.property("Size").setValue(size);
|
|
113
|
-
} else if (shapeType === "ellipse") {
|
|
114
|
-
shapePathProperty = groupContents.addProperty("ADBE Vector Shape - Ellipse");
|
|
115
|
-
shapePathProperty.property("Size").setValue(size);
|
|
116
|
-
} else if (shapeType === "polygon" || shapeType === "star") {
|
|
117
|
-
shapePathProperty = groupContents.addProperty("ADBE Vector Shape - Star");
|
|
118
|
-
shapePathProperty.property("Type").setValue(shapeType === "polygon" ? 1 : 2);
|
|
119
|
-
shapePathProperty.property("Points").setValue(points);
|
|
120
|
-
shapePathProperty.property("Outer Radius").setValue(size[0] / 2);
|
|
121
|
-
if (shapeType === "star") { shapePathProperty.property("Inner Radius").setValue(size[0] / 3); }
|
|
122
|
-
}
|
|
123
|
-
var fill = groupContents.addProperty("ADBE Vector Graphic - Fill");
|
|
124
|
-
fill.property("Color").setValue(fillColor);
|
|
125
|
-
fill.property("Opacity").setValue(100);
|
|
126
|
-
if (strokeWidth > 0) {
|
|
127
|
-
var stroke = groupContents.addProperty("ADBE Vector Graphic - Stroke");
|
|
128
|
-
stroke.property("Color").setValue(strokeColor);
|
|
129
|
-
stroke.property("Stroke Width").setValue(strokeWidth);
|
|
130
|
-
stroke.property("Opacity").setValue(100);
|
|
131
|
-
}
|
|
132
|
-
shapeLayer.property("Position").setValue(position);
|
|
133
|
-
shapeLayer.startTime = startTime;
|
|
134
|
-
if (duration > 0) { shapeLayer.outPoint = startTime + duration; }
|
|
135
|
-
return JSON.stringify({
|
|
136
|
-
status: "success", message: "Shape layer created successfully",
|
|
137
|
-
layer: { name: shapeLayer.name, index: shapeLayer.index, type: "shape", shapeType: shapeType, inPoint: shapeLayer.inPoint, outPoint: shapeLayer.outPoint, position: shapeLayer.property("Position").value }
|
|
138
|
-
}, null, 2);
|
|
139
|
-
} catch (error) {
|
|
140
|
-
return JSON.stringify({ status: "error", message: error.toString() }, null, 2);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// --- createCamera ---
|
|
145
|
-
function createCamera(args) {
|
|
146
|
-
try {
|
|
147
|
-
var compName = args.compName || "";
|
|
148
|
-
var name = args.name || "Camera";
|
|
149
|
-
var zoom = args.zoom || 1777.78; // Default ~50mm equivalent
|
|
150
|
-
var position = args.position; // Optional [x, y, z]
|
|
151
|
-
var pointOfInterest = args.pointOfInterest; // Optional [x, y, z]
|
|
152
|
-
var oneNode = args.oneNode || false; // If true, create a one-node camera (no point of interest)
|
|
153
|
-
|
|
154
|
-
var comp = null;
|
|
155
|
-
for (var i = 1; i <= app.project.numItems; i++) {
|
|
156
|
-
var item = app.project.item(i);
|
|
157
|
-
if (item instanceof CompItem && item.name === compName) { comp = item; break; }
|
|
158
|
-
}
|
|
159
|
-
if (!comp) {
|
|
160
|
-
if (app.project.activeItem instanceof CompItem) { comp = app.project.activeItem; }
|
|
161
|
-
else { throw new Error("No composition found with name '" + compName + "' and no active composition"); }
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
var centerPoint = [comp.width / 2, comp.height / 2];
|
|
165
|
-
var cameraLayer = comp.layers.addCamera(name, centerPoint);
|
|
166
|
-
cameraLayer.property("Camera Options").property("Zoom").setValue(zoom);
|
|
167
|
-
|
|
168
|
-
if (oneNode) {
|
|
169
|
-
cameraLayer.autoOrient = AutoOrientType.NO_AUTO_ORIENT;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (position !== undefined && position !== null) {
|
|
173
|
-
cameraLayer.property("Position").setValue(position);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (pointOfInterest !== undefined && pointOfInterest !== null && !oneNode) {
|
|
177
|
-
cameraLayer.property("Point of Interest").setValue(pointOfInterest);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
var result = {
|
|
181
|
-
name: cameraLayer.name,
|
|
182
|
-
index: cameraLayer.index,
|
|
183
|
-
zoom: cameraLayer.property("Camera Options").property("Zoom").value,
|
|
184
|
-
position: cameraLayer.property("Position").value,
|
|
185
|
-
oneNode: oneNode
|
|
186
|
-
};
|
|
187
|
-
if (!oneNode) {
|
|
188
|
-
result.pointOfInterest = cameraLayer.property("Point of Interest").value;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return JSON.stringify({
|
|
192
|
-
status: "success",
|
|
193
|
-
message: "Camera created successfully",
|
|
194
|
-
layer: result
|
|
195
|
-
}, null, 2);
|
|
196
|
-
} catch (error) {
|
|
197
|
-
return JSON.stringify({ status: "error", message: error.toString() }, null, 2);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// --- duplicateLayer ---
|
|
202
|
-
function duplicateLayer(args) {
|
|
203
|
-
try {
|
|
204
|
-
var compName = args.compName || "";
|
|
205
|
-
var layerIndex = args.layerIndex;
|
|
206
|
-
var layerName = args.layerName || "";
|
|
207
|
-
var newName = args.newName; // optional rename
|
|
208
|
-
|
|
209
|
-
var comp = null;
|
|
210
|
-
for (var i = 1; i <= app.project.numItems; i++) {
|
|
211
|
-
var item = app.project.item(i);
|
|
212
|
-
if (item instanceof CompItem && item.name === compName) { comp = item; break; }
|
|
213
|
-
}
|
|
214
|
-
if (!comp) {
|
|
215
|
-
if (app.project.activeItem instanceof CompItem) { comp = app.project.activeItem; }
|
|
216
|
-
else { throw new Error("No composition found with name '" + compName + "' and no active composition"); }
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
var layer = null;
|
|
220
|
-
if (layerIndex !== undefined && layerIndex !== null) {
|
|
221
|
-
if (layerIndex > 0 && layerIndex <= comp.numLayers) { layer = comp.layer(layerIndex); }
|
|
222
|
-
else { throw new Error("Layer index out of bounds: " + layerIndex); }
|
|
223
|
-
} else if (layerName) {
|
|
224
|
-
for (var j = 1; j <= comp.numLayers; j++) {
|
|
225
|
-
if (comp.layer(j).name === layerName) { layer = comp.layer(j); break; }
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
if (!layer) { throw new Error("Layer not found: " + (layerName || "index " + layerIndex)); }
|
|
229
|
-
|
|
230
|
-
var newLayer = layer.duplicate();
|
|
231
|
-
if (newName) { newLayer.name = newName; }
|
|
232
|
-
|
|
233
|
-
return JSON.stringify({
|
|
234
|
-
status: "success",
|
|
235
|
-
message: "Layer duplicated successfully",
|
|
236
|
-
original: { name: layer.name, index: layer.index },
|
|
237
|
-
duplicate: { name: newLayer.name, index: newLayer.index }
|
|
238
|
-
}, null, 2);
|
|
239
|
-
} catch (error) {
|
|
240
|
-
return JSON.stringify({ status: "error", message: error.toString() }, null, 2);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// --- deleteLayer ---
|
|
245
|
-
function deleteLayer(args) {
|
|
246
|
-
try {
|
|
247
|
-
var compName = args.compName || "";
|
|
248
|
-
var layerIndex = args.layerIndex;
|
|
249
|
-
var layerName = args.layerName || "";
|
|
250
|
-
|
|
251
|
-
var comp = null;
|
|
252
|
-
for (var i = 1; i <= app.project.numItems; i++) {
|
|
253
|
-
var item = app.project.item(i);
|
|
254
|
-
if (item instanceof CompItem && item.name === compName) { comp = item; break; }
|
|
255
|
-
}
|
|
256
|
-
if (!comp) {
|
|
257
|
-
if (app.project.activeItem instanceof CompItem) { comp = app.project.activeItem; }
|
|
258
|
-
else { throw new Error("No composition found with name '" + compName + "' and no active composition"); }
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
var layer = null;
|
|
262
|
-
if (layerIndex !== undefined && layerIndex !== null) {
|
|
263
|
-
if (layerIndex > 0 && layerIndex <= comp.numLayers) { layer = comp.layer(layerIndex); }
|
|
264
|
-
else { throw new Error("Layer index out of bounds: " + layerIndex); }
|
|
265
|
-
} else if (layerName) {
|
|
266
|
-
for (var j = 1; j <= comp.numLayers; j++) {
|
|
267
|
-
if (comp.layer(j).name === layerName) { layer = comp.layer(j); break; }
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
if (!layer) { throw new Error("Layer not found: " + (layerName || "index " + layerIndex)); }
|
|
271
|
-
|
|
272
|
-
var deletedName = layer.name;
|
|
273
|
-
var deletedIndex = layer.index;
|
|
274
|
-
layer.remove();
|
|
275
|
-
|
|
276
|
-
return JSON.stringify({
|
|
277
|
-
status: "success",
|
|
278
|
-
message: "Layer deleted successfully",
|
|
279
|
-
deleted: { name: deletedName, index: deletedIndex }
|
|
280
|
-
}, null, 2);
|
|
281
|
-
} catch (error) {
|
|
282
|
-
return JSON.stringify({ status: "error", message: error.toString() }, null, 2);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// --- setLayerMask: create or modify a mask on a layer ---
|
|
287
|
-
function setLayerMask(args) {
|
|
288
|
-
try {
|
|
289
|
-
var compName = args.compName || "";
|
|
290
|
-
var layerIndex = args.layerIndex;
|
|
291
|
-
var layerName = args.layerName || "";
|
|
292
|
-
var maskIndex = args.maskIndex; // optional — if provided, modify existing mask
|
|
293
|
-
var maskPath = args.maskPath; // array of [x, y] points defining the mask shape
|
|
294
|
-
var maskRect = args.maskRect; // shorthand: {top, left, width, height} for rectangular masks
|
|
295
|
-
var maskMode = args.maskMode || "add"; // "add", "subtract", "intersect", "none"
|
|
296
|
-
var maskFeather = args.maskFeather; // optional [x, y] feather
|
|
297
|
-
var maskOpacity = args.maskOpacity; // optional 0-100
|
|
298
|
-
var maskExpansion = args.maskExpansion; // optional pixels
|
|
299
|
-
var maskName = args.maskName; // optional rename
|
|
300
|
-
|
|
301
|
-
var comp = null;
|
|
302
|
-
for (var i = 1; i <= app.project.numItems; i++) {
|
|
303
|
-
var item = app.project.item(i);
|
|
304
|
-
if (item instanceof CompItem && item.name === compName) { comp = item; break; }
|
|
305
|
-
}
|
|
306
|
-
if (!comp) {
|
|
307
|
-
if (app.project.activeItem instanceof CompItem) { comp = app.project.activeItem; }
|
|
308
|
-
else { throw new Error("No composition found with name '" + compName + "' and no active composition"); }
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
var layer = null;
|
|
312
|
-
if (layerIndex !== undefined && layerIndex !== null) {
|
|
313
|
-
if (layerIndex > 0 && layerIndex <= comp.numLayers) { layer = comp.layer(layerIndex); }
|
|
314
|
-
else { throw new Error("Layer index out of bounds: " + layerIndex); }
|
|
315
|
-
} else if (layerName) {
|
|
316
|
-
for (var j = 1; j <= comp.numLayers; j++) {
|
|
317
|
-
if (comp.layer(j).name === layerName) { layer = comp.layer(j); break; }
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
if (!layer) { throw new Error("Layer not found: " + (layerName || "index " + layerIndex)); }
|
|
321
|
-
|
|
322
|
-
// Build the mask shape
|
|
323
|
-
var shapePoints = [];
|
|
324
|
-
if (maskRect) {
|
|
325
|
-
// Rectangle shorthand
|
|
326
|
-
var t = maskRect.top || 0;
|
|
327
|
-
var l = maskRect.left || 0;
|
|
328
|
-
var w = maskRect.width || comp.width;
|
|
329
|
-
var h = maskRect.height || comp.height;
|
|
330
|
-
shapePoints = [[l, t], [l + w, t], [l + w, t + h], [l, t + h]];
|
|
331
|
-
} else if (maskPath && maskPath.length >= 3) {
|
|
332
|
-
shapePoints = maskPath;
|
|
333
|
-
} else {
|
|
334
|
-
throw new Error("Must provide either maskRect or maskPath with at least 3 points");
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// Create the shape object
|
|
338
|
-
var myShape = new Shape();
|
|
339
|
-
var vertices = [];
|
|
340
|
-
for (var p = 0; p < shapePoints.length; p++) {
|
|
341
|
-
vertices.push(shapePoints[p]);
|
|
342
|
-
}
|
|
343
|
-
myShape.vertices = vertices;
|
|
344
|
-
myShape.closed = true;
|
|
345
|
-
|
|
346
|
-
var changed = [];
|
|
347
|
-
var mask;
|
|
348
|
-
|
|
349
|
-
if (maskIndex !== undefined && maskIndex !== null) {
|
|
350
|
-
// Modify existing mask
|
|
351
|
-
if (maskIndex > 0 && maskIndex <= layer.property("Masks").numProperties) {
|
|
352
|
-
mask = layer.property("Masks").property(maskIndex);
|
|
353
|
-
} else {
|
|
354
|
-
throw new Error("Mask index out of bounds: " + maskIndex);
|
|
355
|
-
}
|
|
356
|
-
mask.property("Mask Path").setValue(myShape);
|
|
357
|
-
changed.push("maskPath");
|
|
358
|
-
} else {
|
|
359
|
-
// Create new mask
|
|
360
|
-
mask = layer.property("Masks").addProperty("Mask");
|
|
361
|
-
mask.property("Mask Path").setValue(myShape);
|
|
362
|
-
changed.push("newMask");
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// Set mask mode
|
|
366
|
-
var modes = {
|
|
367
|
-
"none": MaskMode.NONE,
|
|
368
|
-
"add": MaskMode.ADD,
|
|
369
|
-
"subtract": MaskMode.SUBTRACT,
|
|
370
|
-
"intersect": MaskMode.INTERSECT,
|
|
371
|
-
"lighten": MaskMode.LIGHTEN,
|
|
372
|
-
"darken": MaskMode.DARKEN,
|
|
373
|
-
"difference": MaskMode.DIFFERENCE
|
|
374
|
-
};
|
|
375
|
-
if (modes[maskMode] !== undefined) {
|
|
376
|
-
mask.maskMode = modes[maskMode];
|
|
377
|
-
changed.push("maskMode");
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
if (maskFeather !== undefined && maskFeather !== null) {
|
|
381
|
-
mask.property("Mask Feather").setValue(maskFeather);
|
|
382
|
-
changed.push("maskFeather");
|
|
383
|
-
}
|
|
384
|
-
if (maskOpacity !== undefined && maskOpacity !== null) {
|
|
385
|
-
mask.property("Mask Opacity").setValue(maskOpacity);
|
|
386
|
-
changed.push("maskOpacity");
|
|
387
|
-
}
|
|
388
|
-
if (maskExpansion !== undefined && maskExpansion !== null) {
|
|
389
|
-
mask.property("Mask Expansion").setValue(maskExpansion);
|
|
390
|
-
changed.push("maskExpansion");
|
|
391
|
-
}
|
|
392
|
-
if (maskName) {
|
|
393
|
-
mask.name = maskName;
|
|
394
|
-
changed.push("maskName");
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
return JSON.stringify({
|
|
398
|
-
status: "success",
|
|
399
|
-
message: "Mask set successfully",
|
|
400
|
-
layer: { name: layer.name, index: layer.index },
|
|
401
|
-
mask: {
|
|
402
|
-
name: mask.name,
|
|
403
|
-
index: mask.propertyIndex,
|
|
404
|
-
mode: maskMode,
|
|
405
|
-
changedProperties: changed
|
|
406
|
-
}
|
|
407
|
-
}, null, 2);
|
|
408
|
-
} catch (error) {
|
|
409
|
-
return JSON.stringify({ status: "error", message: error.toString() }, null, 2);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
// --- createSolidLayer (from createSolidLayer.jsx) ---
|
|
414
|
-
function createSolidLayer(args) {
|
|
415
|
-
try {
|
|
416
|
-
var compName = args.compName || "";
|
|
417
|
-
var color = args.color || [1, 1, 1];
|
|
418
|
-
var name = args.name || "Solid Layer";
|
|
419
|
-
var position = args.position || [960, 540];
|
|
420
|
-
var size = args.size;
|
|
421
|
-
var startTime = args.startTime || 0;
|
|
422
|
-
var duration = args.duration || 5;
|
|
423
|
-
var isAdjustment = args.isAdjustment || false;
|
|
424
|
-
var comp = null;
|
|
425
|
-
for (var i = 1; i <= app.project.numItems; i++) {
|
|
426
|
-
var item = app.project.item(i);
|
|
427
|
-
if (item instanceof CompItem && item.name === compName) { comp = item; break; }
|
|
428
|
-
}
|
|
429
|
-
if (!comp) {
|
|
430
|
-
if (app.project.activeItem instanceof CompItem) { comp = app.project.activeItem; }
|
|
431
|
-
else { throw new Error("No composition found with name '" + compName + "' and no active composition"); }
|
|
432
|
-
}
|
|
433
|
-
if (!size) { size = [comp.width, comp.height]; }
|
|
434
|
-
var solidLayer;
|
|
435
|
-
if (isAdjustment) {
|
|
436
|
-
solidLayer = comp.layers.addSolid([0, 0, 0], name, size[0], size[1], 1);
|
|
437
|
-
solidLayer.adjustmentLayer = true;
|
|
438
|
-
} else {
|
|
439
|
-
solidLayer = comp.layers.addSolid(color, name, size[0], size[1], 1);
|
|
440
|
-
}
|
|
441
|
-
solidLayer.property("Position").setValue(position);
|
|
442
|
-
solidLayer.startTime = startTime;
|
|
443
|
-
if (duration > 0) { solidLayer.outPoint = startTime + duration; }
|
|
444
|
-
return JSON.stringify({
|
|
445
|
-
status: "success", message: isAdjustment ? "Adjustment layer created successfully" : "Solid layer created successfully",
|
|
446
|
-
layer: { name: solidLayer.name, index: solidLayer.index, type: isAdjustment ? "adjustment" : "solid", inPoint: solidLayer.inPoint, outPoint: solidLayer.outPoint, position: solidLayer.property("Position").value, isAdjustment: solidLayer.adjustmentLayer }
|
|
447
|
-
}, null, 2);
|
|
448
|
-
} catch (error) {
|
|
449
|
-
return JSON.stringify({ status: "error", message: error.toString() }, null, 2);
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
// --- setLayerProperties (modified to handle text properties) ---
|
|
454
|
-
function setLayerProperties(args) {
|
|
455
|
-
try {
|
|
456
|
-
var compName = args.compName || "";
|
|
457
|
-
var layerName = args.layerName || "";
|
|
458
|
-
var layerIndex = args.layerIndex;
|
|
459
|
-
|
|
460
|
-
// General Properties
|
|
461
|
-
var position = args.position;
|
|
462
|
-
var scale = args.scale;
|
|
463
|
-
var rotation = args.rotation;
|
|
464
|
-
var opacity = args.opacity;
|
|
465
|
-
var startTime = args.startTime;
|
|
466
|
-
var duration = args.duration;
|
|
467
|
-
|
|
468
|
-
// Text Specific Properties
|
|
469
|
-
var textContent = args.text; // New: text content
|
|
470
|
-
var fontFamily = args.fontFamily; // New: font family
|
|
471
|
-
var fontSize = args.fontSize; // New: font size
|
|
472
|
-
var fillColor = args.fillColor; // New: font color
|
|
473
|
-
|
|
474
|
-
// Find the composition (same logic as before)
|
|
475
|
-
var comp = null;
|
|
476
|
-
for (var i = 1; i <= app.project.numItems; i++) {
|
|
477
|
-
var item = app.project.item(i);
|
|
478
|
-
if (item instanceof CompItem && item.name === compName) { comp = item; break; }
|
|
479
|
-
}
|
|
480
|
-
if (!comp) {
|
|
481
|
-
if (app.project.activeItem instanceof CompItem) { comp = app.project.activeItem; }
|
|
482
|
-
else { throw new Error("No composition found with name '" + compName + "' and no active composition"); }
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
// Find the layer (same logic as before)
|
|
486
|
-
var layer = null;
|
|
487
|
-
if (layerIndex !== undefined && layerIndex !== null) {
|
|
488
|
-
if (layerIndex > 0 && layerIndex <= comp.numLayers) { layer = comp.layer(layerIndex); }
|
|
489
|
-
else { throw new Error("Layer index out of bounds: " + layerIndex); }
|
|
490
|
-
} else if (layerName) {
|
|
491
|
-
for (var j = 1; j <= comp.numLayers; j++) {
|
|
492
|
-
if (comp.layer(j).name === layerName) { layer = comp.layer(j); break; }
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
if (!layer) { throw new Error("Layer not found: " + (layerName || "index " + layerIndex)); }
|
|
496
|
-
|
|
497
|
-
var changedProperties = [];
|
|
498
|
-
var textDocumentChanged = false;
|
|
499
|
-
var textProp = null;
|
|
500
|
-
var textDocument = null;
|
|
501
|
-
|
|
502
|
-
// --- Text Property Handling ---
|
|
503
|
-
if (layer instanceof TextLayer && (textContent !== undefined || fontFamily !== undefined || fontSize !== undefined || fillColor !== undefined)) {
|
|
504
|
-
var sourceTextProp = layer.property("Source Text");
|
|
505
|
-
if (sourceTextProp && sourceTextProp.value) {
|
|
506
|
-
var currentTextDocument = sourceTextProp.value; // Get the current value
|
|
507
|
-
var updated = false;
|
|
508
|
-
|
|
509
|
-
if (textContent !== undefined && textContent !== null && currentTextDocument.text !== textContent) {
|
|
510
|
-
currentTextDocument.text = textContent;
|
|
511
|
-
changedProperties.push("text");
|
|
512
|
-
updated = true;
|
|
513
|
-
}
|
|
514
|
-
if (fontFamily !== undefined && fontFamily !== null && currentTextDocument.font !== fontFamily) {
|
|
515
|
-
// Add basic validation/logging for font existence if needed
|
|
516
|
-
// try { app.fonts.findFont(fontFamily); } catch (e) { logToPanel("Warning: Font '"+fontFamily+"' might not be installed."); }
|
|
517
|
-
currentTextDocument.font = fontFamily;
|
|
518
|
-
changedProperties.push("fontFamily");
|
|
519
|
-
updated = true;
|
|
520
|
-
}
|
|
521
|
-
if (fontSize !== undefined && fontSize !== null && currentTextDocument.fontSize !== fontSize) {
|
|
522
|
-
currentTextDocument.fontSize = fontSize;
|
|
523
|
-
changedProperties.push("fontSize");
|
|
524
|
-
updated = true;
|
|
525
|
-
}
|
|
526
|
-
// Comparing colors needs care due to potential floating point inaccuracies if set via UI
|
|
527
|
-
// Simple comparison for now
|
|
528
|
-
if (fillColor !== undefined && fillColor !== null &&
|
|
529
|
-
(currentTextDocument.fillColor[0] !== fillColor[0] ||
|
|
530
|
-
currentTextDocument.fillColor[1] !== fillColor[1] ||
|
|
531
|
-
currentTextDocument.fillColor[2] !== fillColor[2])) {
|
|
532
|
-
currentTextDocument.fillColor = fillColor;
|
|
533
|
-
changedProperties.push("fillColor");
|
|
534
|
-
updated = true;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
// Only set the value if something actually changed
|
|
538
|
-
if (updated) {
|
|
539
|
-
try {
|
|
540
|
-
sourceTextProp.setValue(currentTextDocument);
|
|
541
|
-
logToPanel("Applied changes to Text Document for layer: " + layer.name);
|
|
542
|
-
} catch (e) {
|
|
543
|
-
logToPanel("ERROR applying Text Document changes: " + e.toString());
|
|
544
|
-
// Decide if we should throw or just log the error for text properties
|
|
545
|
-
// For now, just log, other properties might still succeed
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
// Store the potentially updated document for the return value
|
|
549
|
-
textDocument = currentTextDocument;
|
|
550
|
-
|
|
551
|
-
} else {
|
|
552
|
-
logToPanel("Warning: Could not access Source Text property for layer: " + layer.name);
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
// --- Enabled/Visible ---
|
|
557
|
-
var enabled = args.enabled;
|
|
558
|
-
if (enabled !== undefined && enabled !== null) { layer.enabled = !!enabled; changedProperties.push("enabled"); }
|
|
559
|
-
|
|
560
|
-
// --- Blend Mode ---
|
|
561
|
-
var blendMode = args.blendMode;
|
|
562
|
-
if (blendMode !== undefined && blendMode !== null) {
|
|
563
|
-
var modes = {
|
|
564
|
-
"normal": BlendingMode.NORMAL,
|
|
565
|
-
"add": BlendingMode.ADD,
|
|
566
|
-
"multiply": BlendingMode.MULTIPLY,
|
|
567
|
-
"screen": BlendingMode.SCREEN,
|
|
568
|
-
"overlay": BlendingMode.OVERLAY,
|
|
569
|
-
"softLight": BlendingMode.SOFT_LIGHT,
|
|
570
|
-
"hardLight": BlendingMode.HARD_LIGHT,
|
|
571
|
-
"colorDodge": BlendingMode.COLOR_DODGE,
|
|
572
|
-
"colorBurn": BlendingMode.COLOR_BURN,
|
|
573
|
-
"darken": BlendingMode.DARKEN,
|
|
574
|
-
"lighten": BlendingMode.LIGHTEN,
|
|
575
|
-
"difference": BlendingMode.DIFFERENCE,
|
|
576
|
-
"exclusion": BlendingMode.EXCLUSION,
|
|
577
|
-
"hue": BlendingMode.HUE,
|
|
578
|
-
"saturation": BlendingMode.SATURATION,
|
|
579
|
-
"color": BlendingMode.COLOR,
|
|
580
|
-
"luminosity": BlendingMode.LUMINOSITY
|
|
581
|
-
};
|
|
582
|
-
if (modes[blendMode] !== undefined) {
|
|
583
|
-
layer.blendingMode = modes[blendMode];
|
|
584
|
-
changedProperties.push("blendMode");
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// --- Track Matte ---
|
|
589
|
-
var trackMatteType = args.trackMatteType;
|
|
590
|
-
if (trackMatteType !== undefined && trackMatteType !== null) {
|
|
591
|
-
// Values: "none", "alpha", "alphaInverted", "luma", "lumaInverted"
|
|
592
|
-
var matteTypes = {
|
|
593
|
-
"none": TrackMatteType.NO_TRACK_MATTE,
|
|
594
|
-
"alpha": TrackMatteType.ALPHA,
|
|
595
|
-
"alphaInverted": TrackMatteType.ALPHA_INVERTED,
|
|
596
|
-
"luma": TrackMatteType.LUMA,
|
|
597
|
-
"lumaInverted": TrackMatteType.LUMA_INVERTED
|
|
598
|
-
};
|
|
599
|
-
if (matteTypes[trackMatteType] !== undefined) {
|
|
600
|
-
layer.trackMatteType = matteTypes[trackMatteType];
|
|
601
|
-
changedProperties.push("trackMatteType");
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
// --- General Property Handling ---
|
|
606
|
-
var threeDLayer = args.threeDLayer;
|
|
607
|
-
if (threeDLayer !== undefined && threeDLayer !== null) { layer.threeDLayer = !!threeDLayer; changedProperties.push("threeDLayer"); }
|
|
608
|
-
if (position !== undefined && position !== null) {
|
|
609
|
-
var posProp = layer.property("Position");
|
|
610
|
-
if (posProp.numKeys > 0) { while (posProp.numKeys > 0) { posProp.removeKey(1); } }
|
|
611
|
-
posProp.setValue(position);
|
|
612
|
-
changedProperties.push("position");
|
|
613
|
-
}
|
|
614
|
-
if (scale !== undefined && scale !== null) { layer.property("Scale").setValue(scale); changedProperties.push("scale"); }
|
|
615
|
-
if (rotation !== undefined && rotation !== null) {
|
|
616
|
-
if (layer.threeDLayer) {
|
|
617
|
-
// For 3D layers, Z rotation is often what's intended by a single value
|
|
618
|
-
layer.property("Z Rotation").setValue(rotation);
|
|
619
|
-
} else {
|
|
620
|
-
layer.property("Rotation").setValue(rotation);
|
|
621
|
-
}
|
|
622
|
-
changedProperties.push("rotation");
|
|
623
|
-
}
|
|
624
|
-
if (opacity !== undefined && opacity !== null) { layer.property("Opacity").setValue(opacity); changedProperties.push("opacity"); }
|
|
625
|
-
if (startTime !== undefined && startTime !== null) { layer.startTime = startTime; changedProperties.push("startTime"); }
|
|
626
|
-
if (duration !== undefined && duration !== null && duration > 0) {
|
|
627
|
-
var actualStartTime = (startTime !== undefined && startTime !== null) ? startTime : layer.startTime;
|
|
628
|
-
layer.outPoint = actualStartTime + duration;
|
|
629
|
-
changedProperties.push("duration");
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
// Return success with updated layer details (including text if changed)
|
|
633
|
-
var returnLayerInfo = {
|
|
634
|
-
name: layer.name,
|
|
635
|
-
index: layer.index,
|
|
636
|
-
threeDLayer: layer.threeDLayer,
|
|
637
|
-
position: layer.property("Position").value,
|
|
638
|
-
scale: layer.property("Scale").value,
|
|
639
|
-
rotation: layer.threeDLayer ? layer.property("Z Rotation").value : layer.property("Rotation").value, // Return appropriate rotation
|
|
640
|
-
opacity: layer.property("Opacity").value,
|
|
641
|
-
inPoint: layer.inPoint,
|
|
642
|
-
outPoint: layer.outPoint,
|
|
643
|
-
changedProperties: changedProperties
|
|
644
|
-
};
|
|
645
|
-
// Add text properties to the return object if it was a text layer
|
|
646
|
-
if (layer instanceof TextLayer && textDocument) {
|
|
647
|
-
returnLayerInfo.text = textDocument.text;
|
|
648
|
-
returnLayerInfo.fontFamily = textDocument.font;
|
|
649
|
-
returnLayerInfo.fontSize = textDocument.fontSize;
|
|
650
|
-
returnLayerInfo.fillColor = textDocument.fillColor;
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
// *** ADDED LOGGING HERE ***
|
|
654
|
-
logToPanel("Final check before return:");
|
|
655
|
-
logToPanel(" Changed Properties: " + changedProperties.join(", "));
|
|
656
|
-
logToPanel(" Return Layer Info Font: " + (returnLayerInfo.fontFamily || "N/A"));
|
|
657
|
-
logToPanel(" TextDocument Font: " + (textDocument ? textDocument.font : "N/A"));
|
|
658
|
-
|
|
659
|
-
return JSON.stringify({
|
|
660
|
-
status: "success", message: "Layer properties updated successfully",
|
|
661
|
-
layer: returnLayerInfo
|
|
662
|
-
}, null, 2);
|
|
663
|
-
} catch (error) {
|
|
664
|
-
// Error handling remains similar, but add more specific checks if needed
|
|
665
|
-
return JSON.stringify({ status: "error", message: error.toString() }, null, 2);
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
// --- batchSetLayerProperties: apply properties to multiple layers in one call ---
|
|
670
|
-
function batchSetLayerProperties(args) {
|
|
671
|
-
try {
|
|
672
|
-
var compName = args.compName || "";
|
|
673
|
-
var operations = args.operations; // Array of {layerIndex, threeDLayer, position, scale, rotation, opacity, ...}
|
|
674
|
-
|
|
675
|
-
if (!operations || !operations.length) {
|
|
676
|
-
throw new Error("No operations provided. Pass an array of {layerIndex, ...properties}");
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
var comp = null;
|
|
680
|
-
for (var i = 1; i <= app.project.numItems; i++) {
|
|
681
|
-
var item = app.project.item(i);
|
|
682
|
-
if (item instanceof CompItem && item.name === compName) { comp = item; break; }
|
|
683
|
-
}
|
|
684
|
-
if (!comp) {
|
|
685
|
-
if (app.project.activeItem instanceof CompItem) { comp = app.project.activeItem; }
|
|
686
|
-
else { throw new Error("No composition found with name '" + compName + "' and no active composition"); }
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
var results = [];
|
|
690
|
-
for (var o = 0; o < operations.length; o++) {
|
|
691
|
-
var op = operations[o];
|
|
692
|
-
var layer = null;
|
|
693
|
-
if (op.layerIndex !== undefined && op.layerIndex !== null) {
|
|
694
|
-
if (op.layerIndex > 0 && op.layerIndex <= comp.numLayers) { layer = comp.layer(op.layerIndex); }
|
|
695
|
-
else { results.push({ layerIndex: op.layerIndex, status: "error", message: "Layer index out of bounds" }); continue; }
|
|
696
|
-
} else if (op.layerName) {
|
|
697
|
-
for (var j = 1; j <= comp.numLayers; j++) {
|
|
698
|
-
if (comp.layer(j).name === op.layerName) { layer = comp.layer(j); break; }
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
if (!layer) { results.push({ layerIndex: op.layerIndex, layerName: op.layerName, status: "error", message: "Layer not found" }); continue; }
|
|
702
|
-
|
|
703
|
-
var changed = [];
|
|
704
|
-
if (op.threeDLayer !== undefined && op.threeDLayer !== null) { layer.threeDLayer = !!op.threeDLayer; changed.push("threeDLayer"); }
|
|
705
|
-
if (op.position !== undefined && op.position !== null) {
|
|
706
|
-
var posProp = layer.property("Position");
|
|
707
|
-
if (posProp.numKeys > 0) {
|
|
708
|
-
while (posProp.numKeys > 0) { posProp.removeKey(1); }
|
|
709
|
-
}
|
|
710
|
-
posProp.setValue(op.position);
|
|
711
|
-
changed.push("position");
|
|
712
|
-
}
|
|
713
|
-
if (op.scale !== undefined && op.scale !== null) { layer.property("Scale").setValue(op.scale); changed.push("scale"); }
|
|
714
|
-
if (op.rotation !== undefined && op.rotation !== null) {
|
|
715
|
-
if (layer.threeDLayer) { layer.property("Z Rotation").setValue(op.rotation); }
|
|
716
|
-
else { layer.property("Rotation").setValue(op.rotation); }
|
|
717
|
-
changed.push("rotation");
|
|
718
|
-
}
|
|
719
|
-
if (op.opacity !== undefined && op.opacity !== null) { layer.property("Opacity").setValue(op.opacity); changed.push("opacity"); }
|
|
720
|
-
if (op.blendMode !== undefined && op.blendMode !== null) {
|
|
721
|
-
var bModes = {"normal":BlendingMode.NORMAL,"add":BlendingMode.ADD,"multiply":BlendingMode.MULTIPLY,"screen":BlendingMode.SCREEN,"overlay":BlendingMode.OVERLAY,"softLight":BlendingMode.SOFT_LIGHT,"hardLight":BlendingMode.HARD_LIGHT,"darken":BlendingMode.DARKEN,"lighten":BlendingMode.LIGHTEN,"difference":BlendingMode.DIFFERENCE};
|
|
722
|
-
if (bModes[op.blendMode] !== undefined) { layer.blendingMode = bModes[op.blendMode]; changed.push("blendMode"); }
|
|
723
|
-
}
|
|
724
|
-
if (op.startTime !== undefined && op.startTime !== null) { layer.startTime = op.startTime; changed.push("startTime"); }
|
|
725
|
-
if (op.outPoint !== undefined && op.outPoint !== null) { layer.outPoint = op.outPoint; changed.push("outPoint"); }
|
|
726
|
-
|
|
727
|
-
results.push({
|
|
728
|
-
layerIndex: layer.index,
|
|
729
|
-
name: layer.name,
|
|
730
|
-
status: "success",
|
|
731
|
-
threeDLayer: layer.threeDLayer,
|
|
732
|
-
position: layer.property("Position").value,
|
|
733
|
-
changedProperties: changed
|
|
734
|
-
});
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
return JSON.stringify({ status: "success", results: results }, null, 2);
|
|
738
|
-
} catch (error) {
|
|
739
|
-
return JSON.stringify({ status: "error", message: error.toString() }, null, 2);
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
/**
|
|
744
|
-
* Sets a keyframe for a specific property on a layer.
|
|
745
|
-
* Indices are 1-based for After Effects collections.
|
|
746
|
-
* @param {number} compIndex - The index of the composition (1-based).
|
|
747
|
-
* @param {number} layerIndex - The index of the layer within the composition (1-based).
|
|
748
|
-
* @param {string} propertyName - The name of the property (e.g., "Position", "Scale", "Rotation", "Opacity").
|
|
749
|
-
* @param {number} timeInSeconds - The time (in seconds) for the keyframe.
|
|
750
|
-
* @param {any} value - The value for the keyframe (e.g., [x, y] for Position, [w, h] for Scale, angle for Rotation, percentage for Opacity).
|
|
751
|
-
* @returns {string} JSON string indicating success or error.
|
|
752
|
-
*/
|
|
753
|
-
function setLayerKeyframe(compIndex, layerIndex, propertyName, timeInSeconds, value) {
|
|
754
|
-
try {
|
|
755
|
-
// Use 1-based indices as per After Effects API
|
|
756
|
-
var comp = app.project.items[compIndex];
|
|
757
|
-
if (!comp || !(comp instanceof CompItem)) {
|
|
758
|
-
return JSON.stringify({ success: false, message: "Composition not found at index " + compIndex });
|
|
759
|
-
}
|
|
760
|
-
var layer = comp.layers[layerIndex];
|
|
761
|
-
if (!layer) {
|
|
762
|
-
return JSON.stringify({ success: false, message: "Layer not found at index " + layerIndex + " in composition '" + comp.name + "'"});
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
var transformGroup = layer.property("Transform");
|
|
766
|
-
if (!transformGroup) {
|
|
767
|
-
return JSON.stringify({ success: false, message: "Transform properties not found for layer '" + layer.name + "' (type: " + layer.matchName + ")." });
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
var property = transformGroup.property(propertyName);
|
|
771
|
-
if (!property) {
|
|
772
|
-
// Check other common property groups if not in Transform
|
|
773
|
-
if (layer.property("Effects") && layer.property("Effects").property(propertyName)) {
|
|
774
|
-
property = layer.property("Effects").property(propertyName);
|
|
775
|
-
} else if (layer.property("Text") && layer.property("Text").property(propertyName)) {
|
|
776
|
-
property = layer.property("Text").property(propertyName);
|
|
777
|
-
} // Add more groups if needed (e.g., Masks, Shapes)
|
|
778
|
-
|
|
779
|
-
if (!property) {
|
|
780
|
-
return JSON.stringify({ success: false, message: "Property '" + propertyName + "' not found on layer '" + layer.name + "'." });
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
// Ensure the property can be keyframed
|
|
786
|
-
if (!property.canVaryOverTime) {
|
|
787
|
-
return JSON.stringify({ success: false, message: "Property '" + propertyName + "' cannot be keyframed." });
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
// Make sure the property is enabled for keyframing
|
|
791
|
-
if (property.numKeys === 0 && !property.isTimeVarying) {
|
|
792
|
-
property.setValueAtTime(comp.time, property.value); // Set initial keyframe if none exist
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
property.setValueAtTime(timeInSeconds, value);
|
|
797
|
-
|
|
798
|
-
return JSON.stringify({ success: true, message: "Keyframe set for '" + propertyName + "' on layer '" + layer.name + "' at " + timeInSeconds + "s." });
|
|
799
|
-
} catch (e) {
|
|
800
|
-
return JSON.stringify({ success: false, message: "Error setting keyframe: " + e.toString() + " (Line: " + e.line + ")" });
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
/**
|
|
806
|
-
* Sets an expression for a specific property on a layer.
|
|
807
|
-
* @param {number} compIndex - The index of the composition (1-based).
|
|
808
|
-
* @param {number} layerIndex - The index of the layer within the composition (1-based).
|
|
809
|
-
* @param {string} propertyName - The name of the property (e.g., "Position", "Scale", "Rotation", "Opacity").
|
|
810
|
-
* @param {string} expressionString - The JavaScript expression string. Use "" to remove expression.
|
|
811
|
-
* @returns {string} JSON string indicating success or error.
|
|
812
|
-
*/
|
|
813
|
-
function setLayerExpression(compIndex, layerIndex, propertyName, expressionString) {
|
|
814
|
-
try {
|
|
815
|
-
// Adjust indices to be 0-based for ExtendScript arrays
|
|
816
|
-
var comp = app.project.items[compIndex];
|
|
817
|
-
if (!comp || !(comp instanceof CompItem)) {
|
|
818
|
-
return JSON.stringify({ success: false, message: "Composition not found at index " + compIndex });
|
|
819
|
-
}
|
|
820
|
-
var layer = comp.layers[layerIndex];
|
|
821
|
-
if (!layer) {
|
|
822
|
-
return JSON.stringify({ success: false, message: "Layer not found at index " + layerIndex + " in composition '" + comp.name + "'"});
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
var transformGroup = layer.property("Transform");
|
|
826
|
-
if (!transformGroup) {
|
|
827
|
-
// Allow expressions on non-transformable layers if property exists elsewhere
|
|
828
|
-
// return JSON.stringify({ success: false, message: "Transform properties not found for layer '" + layer.name + "' (type: " + layer.matchName + ")." });
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
var property = transformGroup ? transformGroup.property(propertyName) : null;
|
|
832
|
-
if (!property) {
|
|
833
|
-
// Check other common property groups if not in Transform
|
|
834
|
-
if (layer.property("Effects") && layer.property("Effects").property(propertyName)) {
|
|
835
|
-
property = layer.property("Effects").property(propertyName);
|
|
836
|
-
} else if (layer.property("Text") && layer.property("Text").property(propertyName)) {
|
|
837
|
-
property = layer.property("Text").property(propertyName);
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
// Search inside individual effects for sub-properties
|
|
841
|
-
if (!property && layer.property("Effects")) {
|
|
842
|
-
var effects = layer.property("Effects");
|
|
843
|
-
for (var ei = 1; ei <= effects.numProperties; ei++) {
|
|
844
|
-
var eff = effects.property(ei);
|
|
845
|
-
try {
|
|
846
|
-
var subProp = eff.property(propertyName);
|
|
847
|
-
if (subProp) { property = subProp; break; }
|
|
848
|
-
} catch (e2) {}
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
if (!property) {
|
|
853
|
-
return JSON.stringify({ success: false, message: "Property '" + propertyName + "' not found on layer '" + layer.name + "'." });
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
if (!property.canSetExpression) {
|
|
858
|
-
return JSON.stringify({ success: false, message: "Property '" + propertyName + "' does not support expressions." });
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
property.expression = expressionString;
|
|
862
|
-
|
|
863
|
-
var action = expressionString === "" ? "removed" : "set";
|
|
864
|
-
return JSON.stringify({ success: true, message: "Expression " + action + " for '" + propertyName + "' on layer '" + layer.name + "'." });
|
|
865
|
-
} catch (e) {
|
|
866
|
-
return JSON.stringify({ success: false, message: "Error setting expression: " + e.toString() + " (Line: " + e.line + ")" });
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
// --- applyEffect (from applyEffect.jsx) ---
|
|
871
|
-
function applyEffect(args) {
|
|
872
|
-
try {
|
|
873
|
-
// Extract parameters
|
|
874
|
-
var compIndex = args.compIndex || 1; // Default to first comp
|
|
875
|
-
var layerIndex = args.layerIndex || 1; // Default to first layer
|
|
876
|
-
var effectName = args.effectName; // Name of the effect to apply
|
|
877
|
-
var effectMatchName = args.effectMatchName; // After Effects internal name (more reliable)
|
|
878
|
-
var effectCategory = args.effectCategory || ""; // Optional category for filtering
|
|
879
|
-
var presetPath = args.presetPath; // Optional path to an effect preset
|
|
880
|
-
var effectSettings = args.effectSettings || {}; // Optional effect parameters
|
|
881
|
-
|
|
882
|
-
if (!effectName && !effectMatchName && !presetPath) {
|
|
883
|
-
throw new Error("You must specify either effectName, effectMatchName, or presetPath");
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
// Find the composition by index
|
|
887
|
-
var comp = app.project.item(compIndex);
|
|
888
|
-
if (!comp || !(comp instanceof CompItem)) {
|
|
889
|
-
throw new Error("Composition not found at index " + compIndex);
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
// Find the layer by index
|
|
893
|
-
var layer = comp.layer(layerIndex);
|
|
894
|
-
if (!layer) {
|
|
895
|
-
throw new Error("Layer not found at index " + layerIndex + " in composition '" + comp.name + "'");
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
var effectResult;
|
|
899
|
-
|
|
900
|
-
// Apply preset if a path is provided
|
|
901
|
-
if (presetPath) {
|
|
902
|
-
var presetFile = new File(presetPath);
|
|
903
|
-
if (!presetFile.exists) {
|
|
904
|
-
throw new Error("Effect preset file not found: " + presetPath);
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
// Apply the preset to the layer
|
|
908
|
-
layer.applyPreset(presetFile);
|
|
909
|
-
effectResult = {
|
|
910
|
-
type: "preset",
|
|
911
|
-
name: presetPath.split('/').pop().split('\\').pop(),
|
|
912
|
-
applied: true
|
|
913
|
-
};
|
|
914
|
-
}
|
|
915
|
-
// Apply effect by match name (more reliable method)
|
|
916
|
-
else if (effectMatchName) {
|
|
917
|
-
var effect = layer.Effects.addProperty(effectMatchName);
|
|
918
|
-
effectResult = {
|
|
919
|
-
type: "effect",
|
|
920
|
-
name: effect.name,
|
|
921
|
-
matchName: effect.matchName,
|
|
922
|
-
index: effect.propertyIndex
|
|
923
|
-
};
|
|
924
|
-
|
|
925
|
-
// Apply settings if provided
|
|
926
|
-
applyEffectSettings(effect, effectSettings);
|
|
927
|
-
}
|
|
928
|
-
// Apply effect by display name
|
|
929
|
-
else {
|
|
930
|
-
// Get the effect from the Effect menu
|
|
931
|
-
var effect = layer.Effects.addProperty(effectName);
|
|
932
|
-
effectResult = {
|
|
933
|
-
type: "effect",
|
|
934
|
-
name: effect.name,
|
|
935
|
-
matchName: effect.matchName,
|
|
936
|
-
index: effect.propertyIndex
|
|
937
|
-
};
|
|
938
|
-
|
|
939
|
-
// Apply settings if provided
|
|
940
|
-
applyEffectSettings(effect, effectSettings);
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
return JSON.stringify({
|
|
944
|
-
status: "success",
|
|
945
|
-
message: "Effect applied successfully",
|
|
946
|
-
effect: effectResult,
|
|
947
|
-
layer: {
|
|
948
|
-
name: layer.name,
|
|
949
|
-
index: layerIndex
|
|
950
|
-
},
|
|
951
|
-
composition: {
|
|
952
|
-
name: comp.name,
|
|
953
|
-
index: compIndex
|
|
954
|
-
}
|
|
955
|
-
}, null, 2);
|
|
956
|
-
} catch (error) {
|
|
957
|
-
return JSON.stringify({
|
|
958
|
-
status: "error",
|
|
959
|
-
message: error.toString()
|
|
960
|
-
}, null, 2);
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
// Helper function to apply effect settings
|
|
965
|
-
function applyEffectSettings(effect, settings) {
|
|
966
|
-
// Skip if no settings are provided
|
|
967
|
-
if (!settings) return;
|
|
968
|
-
var hasKeys = false;
|
|
969
|
-
for (var k in settings) { if (settings.hasOwnProperty(k)) { hasKeys = true; break; } }
|
|
970
|
-
if (!hasKeys) return;
|
|
971
|
-
|
|
972
|
-
// Iterate through all provided settings
|
|
973
|
-
for (var propName in settings) {
|
|
974
|
-
if (settings.hasOwnProperty(propName)) {
|
|
975
|
-
try {
|
|
976
|
-
// Find the property in the effect
|
|
977
|
-
var property = null;
|
|
978
|
-
|
|
979
|
-
// Try direct property access first
|
|
980
|
-
try {
|
|
981
|
-
property = effect.property(propName);
|
|
982
|
-
} catch (e) {
|
|
983
|
-
// If direct access fails, search through all properties
|
|
984
|
-
for (var i = 1; i <= effect.numProperties; i++) {
|
|
985
|
-
var prop = effect.property(i);
|
|
986
|
-
if (prop.name === propName) {
|
|
987
|
-
property = prop;
|
|
988
|
-
break;
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
// Set the property value if found
|
|
994
|
-
if (property && property.setValue) {
|
|
995
|
-
property.setValue(settings[propName]);
|
|
996
|
-
}
|
|
997
|
-
} catch (e) {
|
|
998
|
-
// Log error but continue with other properties
|
|
999
|
-
$.writeln("Error setting effect property '" + propName + "': " + e.toString());
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
// --- applyEffectTemplate (from applyEffectTemplate.jsx) ---
|
|
1006
|
-
function applyEffectTemplate(args) {
|
|
1007
|
-
try {
|
|
1008
|
-
// Extract parameters
|
|
1009
|
-
var compIndex = args.compIndex || 1; // Default to first comp
|
|
1010
|
-
var layerIndex = args.layerIndex || 1; // Default to first layer
|
|
1011
|
-
var templateName = args.templateName; // Name of the template to apply
|
|
1012
|
-
var customSettings = args.customSettings || {}; // Optional customizations
|
|
1013
|
-
|
|
1014
|
-
if (!templateName) {
|
|
1015
|
-
throw new Error("You must specify a templateName");
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
// Find the composition by index
|
|
1019
|
-
var comp = app.project.item(compIndex);
|
|
1020
|
-
if (!comp || !(comp instanceof CompItem)) {
|
|
1021
|
-
throw new Error("Composition not found at index " + compIndex);
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
// Find the layer by index
|
|
1025
|
-
var layer = comp.layer(layerIndex);
|
|
1026
|
-
if (!layer) {
|
|
1027
|
-
throw new Error("Layer not found at index " + layerIndex + " in composition '" + comp.name + "'");
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
// Template definitions
|
|
1031
|
-
var templates = {
|
|
1032
|
-
// Blur effects
|
|
1033
|
-
"gaussian-blur": {
|
|
1034
|
-
effectMatchName: "ADBE Gaussian Blur 2",
|
|
1035
|
-
settings: {
|
|
1036
|
-
"Blurriness": customSettings.blurriness || 20
|
|
1037
|
-
}
|
|
1038
|
-
},
|
|
1039
|
-
"directional-blur": {
|
|
1040
|
-
effectMatchName: "ADBE Directional Blur",
|
|
1041
|
-
settings: {
|
|
1042
|
-
"Direction": customSettings.direction || 0,
|
|
1043
|
-
"Blur Length": customSettings.length || 10
|
|
1044
|
-
}
|
|
1045
|
-
},
|
|
1046
|
-
|
|
1047
|
-
// Color correction effects
|
|
1048
|
-
"color-balance": {
|
|
1049
|
-
effectMatchName: "ADBE Color Balance (HLS)",
|
|
1050
|
-
settings: {
|
|
1051
|
-
"Hue": customSettings.hue || 0,
|
|
1052
|
-
"Lightness": customSettings.lightness || 0,
|
|
1053
|
-
"Saturation": customSettings.saturation || 0
|
|
1054
|
-
}
|
|
1055
|
-
},
|
|
1056
|
-
"brightness-contrast": {
|
|
1057
|
-
effectMatchName: "ADBE Brightness & Contrast 2",
|
|
1058
|
-
settings: {
|
|
1059
|
-
"Brightness": customSettings.brightness || 0,
|
|
1060
|
-
"Contrast": customSettings.contrast || 0,
|
|
1061
|
-
"Use Legacy": false
|
|
1062
|
-
}
|
|
1063
|
-
},
|
|
1064
|
-
"curves": {
|
|
1065
|
-
effectMatchName: "ADBE CurvesCustom",
|
|
1066
|
-
// Curves are complex and would need special handling
|
|
1067
|
-
},
|
|
1068
|
-
|
|
1069
|
-
// Stylistic effects
|
|
1070
|
-
"glow": {
|
|
1071
|
-
effectMatchName: "ADBE Glow",
|
|
1072
|
-
settings: {
|
|
1073
|
-
"Glow Threshold": customSettings.threshold || 50,
|
|
1074
|
-
"Glow Radius": customSettings.radius || 15,
|
|
1075
|
-
"Glow Intensity": customSettings.intensity || 1
|
|
1076
|
-
}
|
|
1077
|
-
},
|
|
1078
|
-
"drop-shadow": {
|
|
1079
|
-
effectMatchName: "ADBE Drop Shadow",
|
|
1080
|
-
settings: {
|
|
1081
|
-
"Shadow Color": customSettings.color || [0, 0, 0, 1],
|
|
1082
|
-
"Opacity": customSettings.opacity || 50,
|
|
1083
|
-
"Direction": customSettings.direction || 135,
|
|
1084
|
-
"Distance": customSettings.distance || 10,
|
|
1085
|
-
"Softness": customSettings.softness || 10
|
|
1086
|
-
}
|
|
1087
|
-
},
|
|
1088
|
-
|
|
1089
|
-
// Common effect chains
|
|
1090
|
-
"cinematic-look": {
|
|
1091
|
-
effects: [
|
|
1092
|
-
{
|
|
1093
|
-
effectMatchName: "ADBE CurvesCustom",
|
|
1094
|
-
settings: {}
|
|
1095
|
-
},
|
|
1096
|
-
{
|
|
1097
|
-
effectMatchName: "ADBE Vibrance",
|
|
1098
|
-
settings: {
|
|
1099
|
-
"Vibrance": 15,
|
|
1100
|
-
"Saturation": -5
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
]
|
|
1104
|
-
},
|
|
1105
|
-
"text-pop": {
|
|
1106
|
-
effects: [
|
|
1107
|
-
{
|
|
1108
|
-
effectMatchName: "ADBE Drop Shadow",
|
|
1109
|
-
settings: {
|
|
1110
|
-
"Shadow Color": [0, 0, 0, 1],
|
|
1111
|
-
"Opacity": 75,
|
|
1112
|
-
"Distance": 5,
|
|
1113
|
-
"Softness": 10
|
|
1114
|
-
}
|
|
1115
|
-
},
|
|
1116
|
-
{
|
|
1117
|
-
effectMatchName: "ADBE Glow",
|
|
1118
|
-
settings: {
|
|
1119
|
-
"Glow Threshold": 50,
|
|
1120
|
-
"Glow Radius": 10,
|
|
1121
|
-
"Glow Intensity": 1.5
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
]
|
|
1125
|
-
}
|
|
1126
|
-
};
|
|
1127
|
-
|
|
1128
|
-
// Check if the requested template exists
|
|
1129
|
-
var template = templates[templateName];
|
|
1130
|
-
if (!template) {
|
|
1131
|
-
var availableTemplates = Object.keys(templates).join(", ");
|
|
1132
|
-
throw new Error("Template '" + templateName + "' not found. Available templates: " + availableTemplates);
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
var appliedEffects = [];
|
|
1136
|
-
|
|
1137
|
-
// Apply single effect or multiple effects based on template structure
|
|
1138
|
-
if (template.effectMatchName) {
|
|
1139
|
-
// Single effect template
|
|
1140
|
-
var effect = layer.Effects.addProperty(template.effectMatchName);
|
|
1141
|
-
|
|
1142
|
-
// Apply settings
|
|
1143
|
-
for (var propName in template.settings) {
|
|
1144
|
-
try {
|
|
1145
|
-
var property = effect.property(propName);
|
|
1146
|
-
if (property) {
|
|
1147
|
-
property.setValue(template.settings[propName]);
|
|
1148
|
-
}
|
|
1149
|
-
} catch (e) {
|
|
1150
|
-
$.writeln("Warning: Could not set " + propName + " on effect " + effect.name + ": " + e);
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
|
-
appliedEffects.push({
|
|
1155
|
-
name: effect.name,
|
|
1156
|
-
matchName: effect.matchName
|
|
1157
|
-
});
|
|
1158
|
-
} else if (template.effects) {
|
|
1159
|
-
// Multiple effects template
|
|
1160
|
-
for (var i = 0; i < template.effects.length; i++) {
|
|
1161
|
-
var effectData = template.effects[i];
|
|
1162
|
-
var effect = layer.Effects.addProperty(effectData.effectMatchName);
|
|
1163
|
-
|
|
1164
|
-
// Apply settings
|
|
1165
|
-
for (var propName in effectData.settings) {
|
|
1166
|
-
try {
|
|
1167
|
-
var property = effect.property(propName);
|
|
1168
|
-
if (property) {
|
|
1169
|
-
property.setValue(effectData.settings[propName]);
|
|
1170
|
-
}
|
|
1171
|
-
} catch (e) {
|
|
1172
|
-
$.writeln("Warning: Could not set " + propName + " on effect " + effect.name + ": " + e);
|
|
1173
|
-
}
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
appliedEffects.push({
|
|
1177
|
-
name: effect.name,
|
|
1178
|
-
matchName: effect.matchName
|
|
1179
|
-
});
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
|
|
1183
|
-
return JSON.stringify({
|
|
1184
|
-
status: "success",
|
|
1185
|
-
message: "Effect template '" + templateName + "' applied successfully",
|
|
1186
|
-
appliedEffects: appliedEffects,
|
|
1187
|
-
layer: {
|
|
1188
|
-
name: layer.name,
|
|
1189
|
-
index: layerIndex
|
|
1190
|
-
},
|
|
1191
|
-
composition: {
|
|
1192
|
-
name: comp.name,
|
|
1193
|
-
index: compIndex
|
|
1194
|
-
}
|
|
1195
|
-
}, null, 2);
|
|
1196
|
-
} catch (error) {
|
|
1197
|
-
return JSON.stringify({
|
|
1198
|
-
status: "error",
|
|
1199
|
-
message: error.toString()
|
|
1200
|
-
}, null, 2);
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1203
|
-
|
|
1204
|
-
// --- End of Function Definitions ---
|
|
1205
|
-
|
|
1206
|
-
// --- Bridge test function to verify communication and effects application ---
|
|
1207
|
-
function bridgeTestEffects(args) {
|
|
1208
|
-
try {
|
|
1209
|
-
var compIndex = (args && args.compIndex) ? args.compIndex : 1;
|
|
1210
|
-
var layerIndex = (args && args.layerIndex) ? args.layerIndex : 1;
|
|
1211
|
-
|
|
1212
|
-
// Apply a light Gaussian Blur
|
|
1213
|
-
var blurRes = JSON.parse(applyEffect({
|
|
1214
|
-
compIndex: compIndex,
|
|
1215
|
-
layerIndex: layerIndex,
|
|
1216
|
-
effectMatchName: "ADBE Gaussian Blur 2",
|
|
1217
|
-
effectSettings: { "Blurriness": 5 }
|
|
1218
|
-
}));
|
|
1219
|
-
|
|
1220
|
-
// Apply a simple drop shadow via template
|
|
1221
|
-
var shadowRes = JSON.parse(applyEffectTemplate({
|
|
1222
|
-
compIndex: compIndex,
|
|
1223
|
-
layerIndex: layerIndex,
|
|
1224
|
-
templateName: "drop-shadow"
|
|
1225
|
-
}));
|
|
1226
|
-
|
|
1227
|
-
return JSON.stringify({
|
|
1228
|
-
status: "success",
|
|
1229
|
-
message: "Bridge test effects applied.",
|
|
1230
|
-
results: [blurRes, shadowRes]
|
|
1231
|
-
}, null, 2);
|
|
1232
|
-
} catch (e) {
|
|
1233
|
-
return JSON.stringify({ status: "error", message: e.toString() }, null, 2);
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
// JSON polyfill for ExtendScript (when JSON is undefined)
|
|
1238
|
-
if (typeof JSON === "undefined") {
|
|
1239
|
-
JSON = {};
|
|
1240
|
-
}
|
|
1241
|
-
if (typeof JSON.parse !== "function") {
|
|
1242
|
-
JSON.parse = function (text) {
|
|
1243
|
-
// Safe-ish fallback for trusted input (our own command file)
|
|
1244
|
-
return eval("(" + text + ")");
|
|
1245
|
-
};
|
|
1246
|
-
}
|
|
1247
|
-
if (typeof JSON.stringify !== "function") {
|
|
1248
|
-
(function () {
|
|
1249
|
-
function esc(str) {
|
|
1250
|
-
return (str + "")
|
|
1251
|
-
.replace(/\\/g, "\\\\")
|
|
1252
|
-
.replace(/"/g, '\\"')
|
|
1253
|
-
.replace(/\n/g, "\\n")
|
|
1254
|
-
.replace(/\r/g, "\\r")
|
|
1255
|
-
.replace(/\t/g, "\\t");
|
|
1256
|
-
}
|
|
1257
|
-
function toJSON(val) {
|
|
1258
|
-
if (val === null) return "null";
|
|
1259
|
-
var t = typeof val;
|
|
1260
|
-
if (t === "number" || t === "boolean") return String(val);
|
|
1261
|
-
if (t === "string") return '"' + esc(val) + '"';
|
|
1262
|
-
if (val instanceof Array) {
|
|
1263
|
-
var a = [];
|
|
1264
|
-
for (var i = 0; i < val.length; i++) a.push(toJSON(val[i]));
|
|
1265
|
-
return "[" + a.join(",") + "]";
|
|
1266
|
-
}
|
|
1267
|
-
if (t === "object") {
|
|
1268
|
-
var props = [];
|
|
1269
|
-
for (var k in val) {
|
|
1270
|
-
if (val.hasOwnProperty(k) && typeof val[k] !== "function" && typeof val[k] !== "undefined") {
|
|
1271
|
-
props.push('"' + esc(k) + '":' + toJSON(val[k]));
|
|
1272
|
-
}
|
|
1273
|
-
}
|
|
1274
|
-
return "{" + props.join(",") + "}";
|
|
1275
|
-
}
|
|
1276
|
-
return "null";
|
|
1277
|
-
}
|
|
1278
|
-
JSON.stringify = function (value, _replacer, _space) {
|
|
1279
|
-
return toJSON(value);
|
|
1280
|
-
};
|
|
1281
|
-
})();
|
|
1282
|
-
}
|
|
1283
|
-
|
|
1284
|
-
// Detect AE version (AE 2025 = version 25.x, AE 2026 = version 26.x)
|
|
1285
|
-
var aeVersion = parseFloat(app.version);
|
|
1286
|
-
var isAE2025OrLater = aeVersion >= 25.0;
|
|
1287
|
-
|
|
1288
|
-
// Always create a floating palette window for AE 2025+
|
|
1289
|
-
var panel = new Window("palette", "MCP Bridge Auto", undefined);
|
|
1290
|
-
panel.orientation = "column";
|
|
1291
|
-
panel.alignChildren = ["fill", "top"];
|
|
1292
|
-
panel.spacing = 10;
|
|
1293
|
-
panel.margins = 16;
|
|
1294
|
-
|
|
1295
|
-
// Status display
|
|
1296
|
-
var statusText = panel.add("statictext", undefined, "Waiting for commands...");
|
|
1297
|
-
statusText.alignment = ["fill", "top"];
|
|
1298
|
-
|
|
1299
|
-
// Add log area
|
|
1300
|
-
var logPanel = panel.add("panel", undefined, "Command Log");
|
|
1301
|
-
logPanel.orientation = "column";
|
|
1302
|
-
logPanel.alignChildren = ["fill", "fill"];
|
|
1303
|
-
var logText = logPanel.add("edittext", undefined, "", {multiline: true, readonly: true});
|
|
1304
|
-
logText.preferredSize.height = 200;
|
|
1305
|
-
|
|
1306
|
-
// AE 2025 warning
|
|
1307
|
-
if (isAE2025OrLater) {
|
|
1308
|
-
var warning = panel.add("statictext", undefined, "AE 2025+: Dockable panels are not supported. Floating window only.");
|
|
1309
|
-
warning.graphics.foregroundColor = warning.graphics.newPen(warning.graphics.PenType.SOLID_COLOR, [1,0.3,0,1], 1);
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
// Auto-run checkbox
|
|
1313
|
-
var autoRunCheckbox = panel.add("checkbox", undefined, "Auto-run commands");
|
|
1314
|
-
autoRunCheckbox.value = true;
|
|
1315
|
-
|
|
1316
|
-
// Check interval (ms)
|
|
1317
|
-
var checkInterval = 2000;
|
|
1318
|
-
var isChecking = false;
|
|
1319
|
-
|
|
1320
|
-
// Command file path - use Documents folder for reliable access
|
|
1321
|
-
function getCommandFilePath() {
|
|
1322
|
-
var userFolder = Folder.myDocuments;
|
|
1323
|
-
var bridgeFolder = new Folder(userFolder.fsName + "/ae-mcp-bridge");
|
|
1324
|
-
if (!bridgeFolder.exists) {
|
|
1325
|
-
bridgeFolder.create();
|
|
1326
|
-
}
|
|
1327
|
-
return bridgeFolder.fsName + "/ae_command.json";
|
|
1328
|
-
}
|
|
1329
|
-
|
|
1330
|
-
// Result file path - use Documents folder for reliable access
|
|
1331
|
-
function getResultFilePath() {
|
|
1332
|
-
var userFolder = Folder.myDocuments;
|
|
1333
|
-
var bridgeFolder = new Folder(userFolder.fsName + "/ae-mcp-bridge");
|
|
1334
|
-
if (!bridgeFolder.exists) {
|
|
1335
|
-
bridgeFolder.create();
|
|
1336
|
-
}
|
|
1337
|
-
return bridgeFolder.fsName + "/ae_mcp_result.json";
|
|
1338
|
-
}
|
|
1339
|
-
|
|
1340
|
-
// --- setCompositionProperties: set duration, frameRate, etc. on active or named comp ---
|
|
1341
|
-
function setCompositionProperties(args) {
|
|
1342
|
-
try {
|
|
1343
|
-
var compName = args.compName || "";
|
|
1344
|
-
var comp = null;
|
|
1345
|
-
for (var i = 1; i <= app.project.numItems; i++) {
|
|
1346
|
-
var item = app.project.item(i);
|
|
1347
|
-
if (item instanceof CompItem && item.name === compName) { comp = item; break; }
|
|
1348
|
-
}
|
|
1349
|
-
if (!comp) {
|
|
1350
|
-
if (app.project.activeItem instanceof CompItem) { comp = app.project.activeItem; }
|
|
1351
|
-
else { throw new Error("No composition found with name '" + compName + "' and no active composition"); }
|
|
1352
|
-
}
|
|
1353
|
-
var changed = [];
|
|
1354
|
-
if (args.duration !== undefined && args.duration !== null) { comp.duration = args.duration; changed.push("duration"); }
|
|
1355
|
-
if (args.frameRate !== undefined && args.frameRate !== null) { comp.frameRate = args.frameRate; changed.push("frameRate"); }
|
|
1356
|
-
if (args.width !== undefined && args.width !== null && args.height !== undefined && args.height !== null) {
|
|
1357
|
-
comp.width = args.width; comp.height = args.height; changed.push("dimensions");
|
|
1358
|
-
}
|
|
1359
|
-
return JSON.stringify({
|
|
1360
|
-
status: "success",
|
|
1361
|
-
composition: { name: comp.name, duration: comp.duration, frameRate: comp.frameRate, width: comp.width, height: comp.height },
|
|
1362
|
-
changedProperties: changed
|
|
1363
|
-
}, null, 2);
|
|
1364
|
-
} catch (error) {
|
|
1365
|
-
return JSON.stringify({ status: "error", message: error.toString() }, null, 2);
|
|
1366
|
-
}
|
|
1367
|
-
}
|
|
1368
|
-
|
|
1369
|
-
// Functions for each script type
|
|
1370
|
-
function getProjectInfo() {
|
|
1371
|
-
var project = app.project;
|
|
1372
|
-
var result = {
|
|
1373
|
-
projectName: project.file ? project.file.name : "Untitled Project",
|
|
1374
|
-
path: project.file ? project.file.fsName : "",
|
|
1375
|
-
numItems: project.numItems,
|
|
1376
|
-
bitsPerChannel: project.bitsPerChannel,
|
|
1377
|
-
timeMode: project.timeDisplayType === TimeDisplayType.FRAMES ? "Frames" : "Timecode",
|
|
1378
|
-
items: []
|
|
1379
|
-
};
|
|
1380
|
-
|
|
1381
|
-
// Count item types
|
|
1382
|
-
var countByType = {
|
|
1383
|
-
compositions: 0,
|
|
1384
|
-
footage: 0,
|
|
1385
|
-
folders: 0,
|
|
1386
|
-
solids: 0
|
|
1387
|
-
};
|
|
1388
|
-
|
|
1389
|
-
// Get item information (limited for performance)
|
|
1390
|
-
for (var i = 1; i <= Math.min(project.numItems, 50); i++) {
|
|
1391
|
-
var item = project.item(i);
|
|
1392
|
-
var itemType = "";
|
|
1393
|
-
|
|
1394
|
-
if (item instanceof CompItem) {
|
|
1395
|
-
itemType = "Composition";
|
|
1396
|
-
countByType.compositions++;
|
|
1397
|
-
} else if (item instanceof FolderItem) {
|
|
1398
|
-
itemType = "Folder";
|
|
1399
|
-
countByType.folders++;
|
|
1400
|
-
} else if (item instanceof FootageItem) {
|
|
1401
|
-
if (item.mainSource instanceof SolidSource) {
|
|
1402
|
-
itemType = "Solid";
|
|
1403
|
-
countByType.solids++;
|
|
1404
|
-
} else {
|
|
1405
|
-
itemType = "Footage";
|
|
1406
|
-
countByType.footage++;
|
|
1407
|
-
}
|
|
1408
|
-
}
|
|
1409
|
-
|
|
1410
|
-
result.items.push({
|
|
1411
|
-
id: item.id,
|
|
1412
|
-
name: item.name,
|
|
1413
|
-
type: itemType
|
|
1414
|
-
});
|
|
1415
|
-
}
|
|
1416
|
-
|
|
1417
|
-
result.itemCounts = countByType;
|
|
1418
|
-
|
|
1419
|
-
// Include active composition metadata if available
|
|
1420
|
-
if (app.project.activeItem instanceof CompItem) {
|
|
1421
|
-
var ac = app.project.activeItem;
|
|
1422
|
-
result.activeComp = {
|
|
1423
|
-
id: ac.id,
|
|
1424
|
-
name: ac.name,
|
|
1425
|
-
width: ac.width,
|
|
1426
|
-
height: ac.height,
|
|
1427
|
-
duration: ac.duration,
|
|
1428
|
-
frameRate: ac.frameRate,
|
|
1429
|
-
numLayers: ac.numLayers
|
|
1430
|
-
};
|
|
1431
|
-
}
|
|
1432
|
-
|
|
1433
|
-
return JSON.stringify(result, null, 2);
|
|
1434
|
-
}
|
|
1435
|
-
|
|
1436
|
-
function listCompositions() {
|
|
1437
|
-
var project = app.project;
|
|
1438
|
-
var result = {
|
|
1439
|
-
compositions: []
|
|
1440
|
-
};
|
|
1441
|
-
|
|
1442
|
-
// Loop through items in the project
|
|
1443
|
-
for (var i = 1; i <= project.numItems; i++) {
|
|
1444
|
-
var item = project.item(i);
|
|
1445
|
-
|
|
1446
|
-
// Check if the item is a composition
|
|
1447
|
-
if (item instanceof CompItem) {
|
|
1448
|
-
result.compositions.push({
|
|
1449
|
-
id: item.id,
|
|
1450
|
-
name: item.name,
|
|
1451
|
-
duration: item.duration,
|
|
1452
|
-
frameRate: item.frameRate,
|
|
1453
|
-
width: item.width,
|
|
1454
|
-
height: item.height,
|
|
1455
|
-
numLayers: item.numLayers
|
|
1456
|
-
});
|
|
1457
|
-
}
|
|
1458
|
-
}
|
|
1459
|
-
|
|
1460
|
-
return JSON.stringify(result, null, 2);
|
|
1461
|
-
}
|
|
1462
|
-
|
|
1463
|
-
function getLayerInfo() {
|
|
1464
|
-
var project = app.project;
|
|
1465
|
-
var result = {
|
|
1466
|
-
layers: []
|
|
1467
|
-
};
|
|
1468
|
-
|
|
1469
|
-
// Get the active composition
|
|
1470
|
-
var activeComp = null;
|
|
1471
|
-
if (app.project.activeItem instanceof CompItem) {
|
|
1472
|
-
activeComp = app.project.activeItem;
|
|
1473
|
-
} else {
|
|
1474
|
-
return JSON.stringify({ error: "No active composition" }, null, 2);
|
|
1475
|
-
}
|
|
1476
|
-
|
|
1477
|
-
// Loop through layers in the active composition
|
|
1478
|
-
for (var i = 1; i <= activeComp.numLayers; i++) {
|
|
1479
|
-
var layer = activeComp.layer(i);
|
|
1480
|
-
var layerInfo = {
|
|
1481
|
-
index: layer.index,
|
|
1482
|
-
name: layer.name,
|
|
1483
|
-
enabled: layer.enabled,
|
|
1484
|
-
locked: layer.locked,
|
|
1485
|
-
threeDLayer: layer.threeDLayer,
|
|
1486
|
-
position: layer.property("Position").value,
|
|
1487
|
-
inPoint: layer.inPoint,
|
|
1488
|
-
outPoint: layer.outPoint
|
|
1489
|
-
};
|
|
1490
|
-
|
|
1491
|
-
result.layers.push(layerInfo);
|
|
1492
|
-
}
|
|
1493
|
-
|
|
1494
|
-
return JSON.stringify(result, null, 2);
|
|
1495
|
-
}
|
|
1496
|
-
|
|
1497
|
-
// Execute command
|
|
1498
|
-
function executeCommand(command, args) {
|
|
1499
|
-
var result = "";
|
|
1500
|
-
|
|
1501
|
-
logToPanel("Executing command: " + command);
|
|
1502
|
-
statusText.text = "Running: " + command;
|
|
1503
|
-
panel.update();
|
|
1504
|
-
|
|
1505
|
-
try {
|
|
1506
|
-
logToPanel("Attempting to execute: " + command); // Log before switch
|
|
1507
|
-
// Use a switch statement for clarity
|
|
1508
|
-
switch (command) {
|
|
1509
|
-
case "getProjectInfo":
|
|
1510
|
-
result = getProjectInfo();
|
|
1511
|
-
break;
|
|
1512
|
-
case "listCompositions":
|
|
1513
|
-
result = listCompositions();
|
|
1514
|
-
break;
|
|
1515
|
-
case "getLayerInfo":
|
|
1516
|
-
result = getLayerInfo();
|
|
1517
|
-
break;
|
|
1518
|
-
case "createComposition":
|
|
1519
|
-
logToPanel("Calling createComposition function...");
|
|
1520
|
-
result = createComposition(args);
|
|
1521
|
-
logToPanel("Returned from createComposition.");
|
|
1522
|
-
break;
|
|
1523
|
-
case "createTextLayer":
|
|
1524
|
-
logToPanel("Calling createTextLayer function...");
|
|
1525
|
-
result = createTextLayer(args);
|
|
1526
|
-
logToPanel("Returned from createTextLayer.");
|
|
1527
|
-
break;
|
|
1528
|
-
case "createShapeLayer":
|
|
1529
|
-
logToPanel("Calling createShapeLayer function...");
|
|
1530
|
-
result = createShapeLayer(args);
|
|
1531
|
-
logToPanel("Returned from createShapeLayer. Result type: " + typeof result);
|
|
1532
|
-
break;
|
|
1533
|
-
case "createSolidLayer":
|
|
1534
|
-
logToPanel("Calling createSolidLayer function...");
|
|
1535
|
-
result = createSolidLayer(args);
|
|
1536
|
-
logToPanel("Returned from createSolidLayer.");
|
|
1537
|
-
break;
|
|
1538
|
-
case "setLayerProperties":
|
|
1539
|
-
logToPanel("Calling setLayerProperties function...");
|
|
1540
|
-
result = setLayerProperties(args);
|
|
1541
|
-
logToPanel("Returned from setLayerProperties.");
|
|
1542
|
-
break;
|
|
1543
|
-
case "setLayerKeyframe":
|
|
1544
|
-
logToPanel("Calling setLayerKeyframe function...");
|
|
1545
|
-
result = setLayerKeyframe(args.compIndex, args.layerIndex, args.propertyName, args.timeInSeconds, args.value);
|
|
1546
|
-
logToPanel("Returned from setLayerKeyframe.");
|
|
1547
|
-
break;
|
|
1548
|
-
case "setLayerExpression":
|
|
1549
|
-
logToPanel("Calling setLayerExpression function...");
|
|
1550
|
-
result = setLayerExpression(args.compIndex, args.layerIndex, args.propertyName, args.expressionString);
|
|
1551
|
-
logToPanel("Returned from setLayerExpression.");
|
|
1552
|
-
break;
|
|
1553
|
-
case "applyEffect":
|
|
1554
|
-
logToPanel("Calling applyEffect function...");
|
|
1555
|
-
result = applyEffect(args);
|
|
1556
|
-
logToPanel("Returned from applyEffect.");
|
|
1557
|
-
break;
|
|
1558
|
-
case "applyEffectTemplate":
|
|
1559
|
-
logToPanel("Calling applyEffectTemplate function...");
|
|
1560
|
-
result = applyEffectTemplate(args);
|
|
1561
|
-
logToPanel("Returned from applyEffectTemplate.");
|
|
1562
|
-
break;
|
|
1563
|
-
case "bridgeTestEffects":
|
|
1564
|
-
logToPanel("Calling bridgeTestEffects function...");
|
|
1565
|
-
result = bridgeTestEffects(args);
|
|
1566
|
-
logToPanel("Returned from bridgeTestEffects.");
|
|
1567
|
-
break;
|
|
1568
|
-
case "createCamera":
|
|
1569
|
-
logToPanel("Calling createCamera function...");
|
|
1570
|
-
result = createCamera(args);
|
|
1571
|
-
logToPanel("Returned from createCamera.");
|
|
1572
|
-
break;
|
|
1573
|
-
case "batchSetLayerProperties":
|
|
1574
|
-
logToPanel("Calling batchSetLayerProperties function...");
|
|
1575
|
-
result = batchSetLayerProperties(args);
|
|
1576
|
-
logToPanel("Returned from batchSetLayerProperties.");
|
|
1577
|
-
break;
|
|
1578
|
-
case "setCompositionProperties":
|
|
1579
|
-
logToPanel("Calling setCompositionProperties function...");
|
|
1580
|
-
result = setCompositionProperties(args);
|
|
1581
|
-
logToPanel("Returned from setCompositionProperties.");
|
|
1582
|
-
break;
|
|
1583
|
-
case "duplicateLayer":
|
|
1584
|
-
logToPanel("Calling duplicateLayer function...");
|
|
1585
|
-
result = duplicateLayer(args);
|
|
1586
|
-
logToPanel("Returned from duplicateLayer.");
|
|
1587
|
-
break;
|
|
1588
|
-
case "deleteLayer":
|
|
1589
|
-
logToPanel("Calling deleteLayer function...");
|
|
1590
|
-
result = deleteLayer(args);
|
|
1591
|
-
logToPanel("Returned from deleteLayer.");
|
|
1592
|
-
break;
|
|
1593
|
-
case "setLayerMask":
|
|
1594
|
-
logToPanel("Calling setLayerMask function...");
|
|
1595
|
-
result = setLayerMask(args);
|
|
1596
|
-
logToPanel("Returned from setLayerMask.");
|
|
1597
|
-
break;
|
|
1598
|
-
default:
|
|
1599
|
-
result = JSON.stringify({ error: "Unknown command: " + command });
|
|
1600
|
-
}
|
|
1601
|
-
logToPanel("Execution finished for: " + command); // Log after switch
|
|
1602
|
-
|
|
1603
|
-
// Save the result (ensure result is always a string)
|
|
1604
|
-
logToPanel("Preparing to write result file...");
|
|
1605
|
-
var resultString = (typeof result === 'string') ? result : JSON.stringify(result);
|
|
1606
|
-
|
|
1607
|
-
// Try to parse the result as JSON to add a timestamp
|
|
1608
|
-
try {
|
|
1609
|
-
var resultObj = JSON.parse(resultString);
|
|
1610
|
-
// Add a timestamp to help identify if we're getting fresh results
|
|
1611
|
-
resultObj._responseTimestamp = new Date().toISOString();
|
|
1612
|
-
resultObj._commandExecuted = command;
|
|
1613
|
-
resultString = JSON.stringify(resultObj, null, 2);
|
|
1614
|
-
logToPanel("Added timestamp to result JSON for tracking freshness.");
|
|
1615
|
-
} catch (parseError) {
|
|
1616
|
-
// If it's not valid JSON, append the timestamp as a comment
|
|
1617
|
-
logToPanel("Could not parse result as JSON to add timestamp: " + parseError.toString());
|
|
1618
|
-
// We'll still continue with the original string
|
|
1619
|
-
}
|
|
1620
|
-
|
|
1621
|
-
var resultFile = new File(getResultFilePath());
|
|
1622
|
-
resultFile.encoding = "UTF-8"; // Ensure UTF-8 encoding
|
|
1623
|
-
logToPanel("Opening result file for writing...");
|
|
1624
|
-
var opened = resultFile.open("w");
|
|
1625
|
-
if (!opened) {
|
|
1626
|
-
logToPanel("ERROR: Failed to open result file for writing: " + resultFile.fsName);
|
|
1627
|
-
throw new Error("Failed to open result file for writing.");
|
|
1628
|
-
}
|
|
1629
|
-
logToPanel("Writing to result file...");
|
|
1630
|
-
var written = resultFile.write(resultString);
|
|
1631
|
-
if (!written) {
|
|
1632
|
-
logToPanel("ERROR: Failed to write to result file (write returned false): " + resultFile.fsName);
|
|
1633
|
-
// Still try to close, but log the error
|
|
1634
|
-
}
|
|
1635
|
-
logToPanel("Closing result file...");
|
|
1636
|
-
var closed = resultFile.close();
|
|
1637
|
-
if (!closed) {
|
|
1638
|
-
logToPanel("ERROR: Failed to close result file: " + resultFile.fsName);
|
|
1639
|
-
// Continue, but log the error
|
|
1640
|
-
}
|
|
1641
|
-
logToPanel("Result file write process complete.");
|
|
1642
|
-
|
|
1643
|
-
logToPanel("Command completed successfully: " + command); // Changed log message
|
|
1644
|
-
statusText.text = "Command completed: " + command;
|
|
1645
|
-
|
|
1646
|
-
// Update command file status
|
|
1647
|
-
logToPanel("Updating command status to completed...");
|
|
1648
|
-
updateCommandStatus("completed");
|
|
1649
|
-
logToPanel("Command status updated.");
|
|
1650
|
-
|
|
1651
|
-
} catch (error) {
|
|
1652
|
-
var errorMsg = "ERROR in executeCommand for '" + command + "': " + error.toString() + (error.line ? " (line: " + error.line + ")" : "");
|
|
1653
|
-
logToPanel(errorMsg); // Log detailed error
|
|
1654
|
-
statusText.text = "Error: " + error.toString();
|
|
1655
|
-
|
|
1656
|
-
// Write detailed error to result file
|
|
1657
|
-
try {
|
|
1658
|
-
logToPanel("Attempting to write ERROR to result file...");
|
|
1659
|
-
var errorResult = JSON.stringify({
|
|
1660
|
-
status: "error",
|
|
1661
|
-
command: command,
|
|
1662
|
-
message: error.toString(),
|
|
1663
|
-
line: error.line,
|
|
1664
|
-
fileName: error.fileName
|
|
1665
|
-
});
|
|
1666
|
-
var errorFile = new File(getResultFilePath());
|
|
1667
|
-
errorFile.encoding = "UTF-8";
|
|
1668
|
-
if (errorFile.open("w")) {
|
|
1669
|
-
errorFile.write(errorResult);
|
|
1670
|
-
errorFile.close();
|
|
1671
|
-
logToPanel("Successfully wrote ERROR to result file.");
|
|
1672
|
-
} else {
|
|
1673
|
-
logToPanel("CRITICAL ERROR: Failed to open result file to write error!");
|
|
1674
|
-
}
|
|
1675
|
-
} catch (writeError) {
|
|
1676
|
-
logToPanel("CRITICAL ERROR: Failed to write error to result file: " + writeError.toString());
|
|
1677
|
-
}
|
|
1678
|
-
|
|
1679
|
-
// Update command file status even after error
|
|
1680
|
-
logToPanel("Updating command status to error...");
|
|
1681
|
-
updateCommandStatus("error");
|
|
1682
|
-
logToPanel("Command status updated to error.");
|
|
1683
|
-
}
|
|
1684
|
-
}
|
|
1685
|
-
|
|
1686
|
-
// Update command file status
|
|
1687
|
-
function updateCommandStatus(status) {
|
|
1688
|
-
try {
|
|
1689
|
-
var commandFile = new File(getCommandFilePath());
|
|
1690
|
-
if (commandFile.exists) {
|
|
1691
|
-
commandFile.open("r");
|
|
1692
|
-
var content = commandFile.read();
|
|
1693
|
-
commandFile.close();
|
|
1694
|
-
|
|
1695
|
-
if (content) {
|
|
1696
|
-
var commandData = JSON.parse(content);
|
|
1697
|
-
commandData.status = status;
|
|
1698
|
-
|
|
1699
|
-
commandFile.open("w");
|
|
1700
|
-
commandFile.write(JSON.stringify(commandData, null, 2));
|
|
1701
|
-
commandFile.close();
|
|
1702
|
-
}
|
|
1703
|
-
}
|
|
1704
|
-
} catch (e) {
|
|
1705
|
-
logToPanel("Error updating command status: " + e.toString());
|
|
1706
|
-
}
|
|
1707
|
-
}
|
|
1708
|
-
|
|
1709
|
-
// Log message to panel
|
|
1710
|
-
function logToPanel(message) {
|
|
1711
|
-
var timestamp = new Date().toLocaleTimeString();
|
|
1712
|
-
logText.text = timestamp + ": " + message + "\n" + logText.text;
|
|
1713
|
-
}
|
|
1714
|
-
|
|
1715
|
-
// Check for new commands
|
|
1716
|
-
function checkForCommands() {
|
|
1717
|
-
if (!autoRunCheckbox.value || isChecking) return;
|
|
1718
|
-
|
|
1719
|
-
isChecking = true;
|
|
1720
|
-
|
|
1721
|
-
try {
|
|
1722
|
-
var commandFile = new File(getCommandFilePath());
|
|
1723
|
-
if (commandFile.exists) {
|
|
1724
|
-
commandFile.open("r");
|
|
1725
|
-
var content = commandFile.read();
|
|
1726
|
-
commandFile.close();
|
|
1727
|
-
|
|
1728
|
-
if (content) {
|
|
1729
|
-
var commandData = (typeof JSON !== "undefined" && JSON.parse)
|
|
1730
|
-
? JSON.parse(content)
|
|
1731
|
-
: eval("(" + content + ")");
|
|
1732
|
-
|
|
1733
|
-
// Only execute pending commands
|
|
1734
|
-
if (commandData.status === "pending") {
|
|
1735
|
-
// Update status to running
|
|
1736
|
-
updateCommandStatus("running");
|
|
1737
|
-
|
|
1738
|
-
// Execute the command
|
|
1739
|
-
executeCommand(commandData.command, commandData.args || {});
|
|
1740
|
-
}
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
} catch (e) {
|
|
1744
|
-
logToPanel("Error checking for commands: " + e.toString());
|
|
1745
|
-
}
|
|
1746
|
-
|
|
1747
|
-
isChecking = false;
|
|
1748
|
-
}
|
|
1749
|
-
|
|
1750
|
-
// Set up timer to check for commands
|
|
1751
|
-
function startCommandChecker() {
|
|
1752
|
-
app.scheduleTask("checkForCommands()", checkInterval, true);
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
|
-
// Add manual check button
|
|
1756
|
-
var checkButton = panel.add("button", undefined, "Check for Commands Now");
|
|
1757
|
-
checkButton.onClick = function() {
|
|
1758
|
-
logToPanel("Manually checking for commands");
|
|
1759
|
-
checkForCommands();
|
|
1760
|
-
};
|
|
1761
|
-
|
|
1762
|
-
// Log startup
|
|
1763
|
-
logToPanel("MCP Bridge Auto started");
|
|
1764
|
-
logToPanel("Command file: " + getCommandFilePath());
|
|
1765
|
-
statusText.text = "Ready - Auto-run is " + (autoRunCheckbox.value ? "ON" : "OFF");
|
|
1766
|
-
|
|
1767
|
-
// Start the command checker
|
|
1768
|
-
startCommandChecker();
|
|
1769
|
-
|
|
1770
|
-
// Show the panel
|
|
1771
|
-
panel.center();
|
|
1772
|
-
panel.show();
|
|
1773
|
-
|