creavit-studio-mcp 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -0
- package/package.json +1 -1
- package/src/appLauncher.mjs +104 -0
- package/src/bridgeClient.mjs +33 -5
- package/src/tools/browserTools.mjs +5 -1
- package/src/tools/index.mjs +2 -0
- package/src/tools/motion/elementTools.mjs +157 -0
- package/src/tools/motion/sessionTools.mjs +151 -0
- package/src/tools/motion/timelineTools.mjs +54 -0
- package/src/tools/motionTools.mjs +11 -0
- package/src/tools/systemTools.mjs +30 -2
package/README.md
CHANGED
|
@@ -118,6 +118,27 @@ files directly and work with the app closed.
|
|
|
118
118
|
`creavit_editor_add_perspective`, `creavit_editor_update_perspective`,
|
|
119
119
|
`creavit_editor_remove_perspective`
|
|
120
120
|
|
|
121
|
+
**Motion Studio** — session: `creavit_motion_state`, `creavit_motion_open`,
|
|
122
|
+
`creavit_motion_save`, `creavit_motion_close`, `creavit_motion_scene_get`,
|
|
123
|
+
`creavit_motion_scene_set`, `creavit_motion_playback`,
|
|
124
|
+
`creavit_motion_screenshot`, `creavit_motion_history`, `creavit_motion_export`,
|
|
125
|
+
`creavit_motion_import`
|
|
126
|
+
|
|
127
|
+
Elements: `creavit_motion_elements`, `creavit_motion_element_get`,
|
|
128
|
+
`creavit_motion_element_add`, `creavit_motion_element_update`,
|
|
129
|
+
`creavit_motion_element_remove`, `creavit_motion_element_arrange`,
|
|
130
|
+
`creavit_motion_select`
|
|
131
|
+
|
|
132
|
+
Animation: `creavit_motion_presets`, `creavit_motion_action_add`,
|
|
133
|
+
`creavit_motion_action_update`, `creavit_motion_action_remove`
|
|
134
|
+
|
|
135
|
+
Timeline & assets: `creavit_motion_segments`, `creavit_motion_library`,
|
|
136
|
+
`creavit_motion_templates`
|
|
137
|
+
|
|
138
|
+
> Motion Studio is a mode **inside** the editor window: open a project first,
|
|
139
|
+
> then `creavit_motion_open`. `creavit_motion_segments` also works with Motion
|
|
140
|
+
> Studio closed.
|
|
141
|
+
|
|
121
142
|
**Recording** — `creavit_devices_list`, `creavit_recording_status`,
|
|
122
143
|
`creavit_recording_start`, `creavit_recording_stop`
|
|
123
144
|
|
|
@@ -162,6 +183,25 @@ creavit_project_save
|
|
|
162
183
|
`creavit_editor_audio action=mute` changes both preview audio and every clip's
|
|
163
184
|
timeline volume, so the saved project also exports without source audio.
|
|
164
185
|
|
|
186
|
+
### Motion Studio
|
|
187
|
+
|
|
188
|
+
```text
|
|
189
|
+
creavit_motion_segments action=list what motion overlays exist
|
|
190
|
+
creavit_motion_open new=true startTime=2 new scene at 2s on the timeline
|
|
191
|
+
creavit_motion_presets the animation catalog
|
|
192
|
+
creavit_motion_element_add kind=text patch={text:"Hello", fontSize:64}
|
|
193
|
+
creavit_motion_action_add elementId=... presetId=slide-in-up
|
|
194
|
+
creavit_motion_screenshot time=0.4 VERIFY the animation
|
|
195
|
+
creavit_motion_save write back to the segment
|
|
196
|
+
creavit_motion_close return to the editor
|
|
197
|
+
creavit_project_save persist
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
`creavit_motion_export` renders the scene on its own (video / gif / json /
|
|
201
|
+
lottie / html) into the Downloads folder — that is separate from
|
|
202
|
+
`creavit_editor_export`, which renders the whole video with the motion overlay
|
|
203
|
+
composited in.
|
|
204
|
+
|
|
165
205
|
### Record a URL walkthrough
|
|
166
206
|
|
|
167
207
|
`creavit_record_url_walkthrough` is the high-level workflow. By default it opens
|
package/package.json
CHANGED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// MCP sunucusu — uygulama kapalıysa başlatma.
|
|
2
|
+
//
|
|
3
|
+
// Köprü yalnızca uygulama çalışırken vardır. Ajanın "önce uygulamayı sen aç"
|
|
4
|
+
// diyememesi her oturumun başında elle müdahale gerektiriyordu. Burası
|
|
5
|
+
// uygulamayı bulur, açar ve köprü hazır olana kadar bekler.
|
|
6
|
+
|
|
7
|
+
import { spawn } from "node:child_process";
|
|
8
|
+
import fs from "node:fs";
|
|
9
|
+
import os from "node:os";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
|
|
12
|
+
const APP_BUNDLE_NAME = "Creavit Studio.app";
|
|
13
|
+
|
|
14
|
+
const DEFAULT_APP_PATHS = [
|
|
15
|
+
path.join("/Applications", APP_BUNDLE_NAME),
|
|
16
|
+
path.join(os.homedir(), "Applications", APP_BUNDLE_NAME),
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
/** Açılışın tamamlanması için verilen süre; soğuk başlangıç yavaş olabilir. */
|
|
20
|
+
export const DEFAULT_LAUNCH_TIMEOUT_MS = 45_000;
|
|
21
|
+
const POLL_INTERVAL_MS = 500;
|
|
22
|
+
|
|
23
|
+
export class AppLaunchError extends Error {
|
|
24
|
+
constructor(message) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.name = "AppLaunchError";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Uygulama paketinin yolu: env override > /Applications > ~/Applications */
|
|
31
|
+
export function resolveAppPath() {
|
|
32
|
+
const fromEnv = process.env.CREAVIT_APP_PATH;
|
|
33
|
+
const candidates = fromEnv ? [fromEnv, ...DEFAULT_APP_PATHS] : DEFAULT_APP_PATHS;
|
|
34
|
+
|
|
35
|
+
for (const candidate of candidates) {
|
|
36
|
+
try {
|
|
37
|
+
if (candidate && fs.existsSync(candidate)) return candidate;
|
|
38
|
+
} catch (_) {}
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Otomatik başlatma kapatılabilir olmalı (CI, kısıtlı ortam). */
|
|
44
|
+
export function isAutoLaunchEnabled() {
|
|
45
|
+
return process.env.CREAVIT_MCP_AUTOLAUNCH !== "0";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Uygulamayı açar (beklemez). macOS'ta `open` kullanılır: zaten açıksa yeni
|
|
52
|
+
* kopya başlatmaz, kapalıysa başlatır.
|
|
53
|
+
*/
|
|
54
|
+
export function launchApp() {
|
|
55
|
+
if (process.platform !== "darwin") {
|
|
56
|
+
throw new AppLaunchError(
|
|
57
|
+
"Automatic launch is only supported on macOS. Start Creavit Studio manually.",
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const appPath = resolveAppPath();
|
|
62
|
+
if (!appPath) {
|
|
63
|
+
throw new AppLaunchError(
|
|
64
|
+
`Could not find ${APP_BUNDLE_NAME} in /Applications or ~/Applications. ` +
|
|
65
|
+
"Set CREAVIT_APP_PATH to the bundle path, or start the app manually.",
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const child = spawn("open", ["-a", appPath], {
|
|
70
|
+
detached: true,
|
|
71
|
+
stdio: "ignore",
|
|
72
|
+
});
|
|
73
|
+
child.unref();
|
|
74
|
+
return appPath;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Uygulama çalışmıyorsa başlatır ve köprü yanıt verene kadar bekler.
|
|
79
|
+
*
|
|
80
|
+
* @param {object} options
|
|
81
|
+
* @param {() => Promise<boolean>} options.isRunning Köprü sağlık kontrolü
|
|
82
|
+
* @param {number} [options.timeoutMs]
|
|
83
|
+
* @returns {Promise<{ launched: boolean, appPath: string|null }>}
|
|
84
|
+
*/
|
|
85
|
+
export async function ensureAppRunning({
|
|
86
|
+
isRunning,
|
|
87
|
+
timeoutMs = DEFAULT_LAUNCH_TIMEOUT_MS,
|
|
88
|
+
}) {
|
|
89
|
+
if (await isRunning()) return { launched: false, appPath: null };
|
|
90
|
+
|
|
91
|
+
const appPath = launchApp();
|
|
92
|
+
const deadline = Date.now() + timeoutMs;
|
|
93
|
+
|
|
94
|
+
while (Date.now() < deadline) {
|
|
95
|
+
await delay(POLL_INTERVAL_MS);
|
|
96
|
+
if (await isRunning()) return { launched: true, appPath };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
throw new AppLaunchError(
|
|
100
|
+
`Launched ${appPath} but its agent bridge did not become ready within ` +
|
|
101
|
+
`${Math.round(timeoutMs / 1000)}s. The app may still be starting, or the ` +
|
|
102
|
+
"bridge may be disabled (CREAVIT_AGENT_BRIDGE=0).",
|
|
103
|
+
);
|
|
104
|
+
}
|
package/src/bridgeClient.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import fs from "node:fs";
|
|
|
7
7
|
import os from "node:os";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import { ENDPOINT_FILENAME, APP_NOT_RUNNING_HINT } from "./protocol.mjs";
|
|
10
|
+
import { ensureAppRunning, isAutoLaunchEnabled } from "./appLauncher.mjs";
|
|
10
11
|
|
|
11
12
|
const DEFAULT_ENDPOINT_DIRS = [
|
|
12
13
|
path.join(os.homedir(), "Library", "Application Support", "creavit-studio"),
|
|
@@ -107,12 +108,39 @@ async function request(route, { method = "GET", body, timeoutMs = 120_000 } = {}
|
|
|
107
108
|
return payload.result;
|
|
108
109
|
}
|
|
109
110
|
|
|
111
|
+
// Otomatik başlatma süreç başına EN FAZLA BİR KEZ denenir. Her başarısız
|
|
112
|
+
// çağrıda yeniden denemek, uygulama gerçekten açılamıyorsa her aracı
|
|
113
|
+
// dakikalarca bekletirdi.
|
|
114
|
+
let autoLaunchAttempt = null;
|
|
115
|
+
|
|
116
|
+
async function tryAutoLaunch() {
|
|
117
|
+
if (!isAutoLaunchEnabled()) return false;
|
|
118
|
+
if (!autoLaunchAttempt) {
|
|
119
|
+
autoLaunchAttempt = ensureAppRunning({ isRunning: isAppRunning })
|
|
120
|
+
.then(() => true)
|
|
121
|
+
.catch(() => false);
|
|
122
|
+
}
|
|
123
|
+
return autoLaunchAttempt;
|
|
124
|
+
}
|
|
125
|
+
|
|
110
126
|
export async function callCommand(command, params, timeoutMs) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
127
|
+
const send = () =>
|
|
128
|
+
request("/rpc", {
|
|
129
|
+
method: "POST",
|
|
130
|
+
body: { command, params: params || {}, timeoutMs },
|
|
131
|
+
timeoutMs: timeoutMs || 120_000,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
return await send();
|
|
136
|
+
} catch (error) {
|
|
137
|
+
// Uygulama kapalıysa aç ve komutu bir kez tekrarla; ajanın "önce
|
|
138
|
+
// uygulamayı elle başlat" demek zorunda kalmaması için.
|
|
139
|
+
if (!(error instanceof BridgeUnavailableError)) throw error;
|
|
140
|
+
const launched = await tryAutoLaunch();
|
|
141
|
+
if (!launched) throw error;
|
|
142
|
+
return send();
|
|
143
|
+
}
|
|
116
144
|
}
|
|
117
145
|
|
|
118
146
|
export async function health() {
|
|
@@ -178,7 +178,8 @@ export function browserTools() {
|
|
|
178
178
|
bridgeTool({
|
|
179
179
|
name: "creavit_browser_interact",
|
|
180
180
|
command: "browser.interact",
|
|
181
|
-
description:
|
|
181
|
+
description:
|
|
182
|
+
"Finds a page element by CSS selector or visible text, scrolls to it, and performs a hover/click/type action. By default it moves the REAL system mouse, which looks natural in a recording. Set useSystemCursor:false when the user asks you not to touch their cursor — the click is still delivered to the page, the pointer just never moves.",
|
|
182
183
|
inputSchema: schema(
|
|
183
184
|
{
|
|
184
185
|
captureWindowId: S.number("Capture window ID"),
|
|
@@ -187,6 +188,9 @@ export function browserTools() {
|
|
|
187
188
|
text: S.string("Visible text fallback"),
|
|
188
189
|
value: S.string("Text to enter for type"),
|
|
189
190
|
moveDurationMs: S.number("Real mouse travel duration (default 520)"),
|
|
191
|
+
useSystemCursor: S.bool(
|
|
192
|
+
"Move the real system cursor (default true). false = never touch the user's pointer; clicks are sent synthetically.",
|
|
193
|
+
),
|
|
190
194
|
},
|
|
191
195
|
["captureWindowId", "action"],
|
|
192
196
|
),
|
package/src/tools/index.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { projectTools } from "./projectTools.mjs";
|
|
4
4
|
import { editorTools } from "./editorTools.mjs";
|
|
5
|
+
import { motionTools } from "./motionTools.mjs";
|
|
5
6
|
import { systemTools } from "./systemTools.mjs";
|
|
6
7
|
import { browserTools } from "./browserTools.mjs";
|
|
7
8
|
import { escapeTools } from "./escapeTools.mjs";
|
|
@@ -16,6 +17,7 @@ function buildRegistry() {
|
|
|
16
17
|
...systemTools(),
|
|
17
18
|
...projectTools(),
|
|
18
19
|
...editorTools(),
|
|
20
|
+
...motionTools(),
|
|
19
21
|
...browserTools(),
|
|
20
22
|
...escapeTools(),
|
|
21
23
|
];
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// MCP araçları — Motion Studio elemanları ve animasyon action'ları.
|
|
2
|
+
|
|
3
|
+
import { bridgeTool, schema, S, textResult } from "../defineTool.mjs";
|
|
4
|
+
|
|
5
|
+
export function motionElementTools() {
|
|
6
|
+
return [
|
|
7
|
+
bridgeTool({
|
|
8
|
+
name: "creavit_motion_elements",
|
|
9
|
+
command: "motion.listElements",
|
|
10
|
+
description:
|
|
11
|
+
"Lists every element in the scene tree (group children included) with id, type, name, bounds, visibility and action count. Start here before editing anything.",
|
|
12
|
+
inputSchema: schema(),
|
|
13
|
+
}),
|
|
14
|
+
|
|
15
|
+
bridgeTool({
|
|
16
|
+
name: "creavit_motion_element_get",
|
|
17
|
+
command: "motion.getElement",
|
|
18
|
+
description:
|
|
19
|
+
"Returns one element in full: every style property plus its animation actions with ids, start times and params.",
|
|
20
|
+
inputSchema: schema({ id: S.string("Element ID") }, ["id"]),
|
|
21
|
+
}),
|
|
22
|
+
|
|
23
|
+
bridgeTool({
|
|
24
|
+
name: "creavit_motion_element_add",
|
|
25
|
+
command: "motion.addElement",
|
|
26
|
+
description:
|
|
27
|
+
"Adds an element to the scene, centered by default. Kinds: text, rect, circle, line, image, icon, group. Pass initial properties in `patch` — e.g. text: {text, fontSize, color, fontFamily, align}, shapes: {fill, cornerRadius}, image: {src, fit}, icon: {iconKind, color}. Verify with creavit_motion_screenshot afterwards.",
|
|
28
|
+
inputSchema: schema(
|
|
29
|
+
{
|
|
30
|
+
kind: S.string("Element kind", {
|
|
31
|
+
enum: ["text", "rect", "circle", "line", "image", "icon", "group"],
|
|
32
|
+
}),
|
|
33
|
+
patch: S.object("Initial properties: x, y, width, height, text, fill, color, fontSize..."),
|
|
34
|
+
parentId: S.string("Group ID to add into (omit for the scene root)"),
|
|
35
|
+
},
|
|
36
|
+
["kind"],
|
|
37
|
+
),
|
|
38
|
+
}),
|
|
39
|
+
|
|
40
|
+
bridgeTool({
|
|
41
|
+
name: "creavit_motion_element_update",
|
|
42
|
+
command: "motion.updateElement",
|
|
43
|
+
description:
|
|
44
|
+
'Partially updates one element. Only the keys you pass change: {"x":100,"y":40,"opacity":0.5,"visible":false}. Read valid key names with creavit_motion_element_get.',
|
|
45
|
+
inputSchema: schema(
|
|
46
|
+
{ id: S.string("Element ID"), patch: S.object("Properties to change") },
|
|
47
|
+
["id", "patch"],
|
|
48
|
+
),
|
|
49
|
+
}),
|
|
50
|
+
|
|
51
|
+
bridgeTool({
|
|
52
|
+
name: "creavit_motion_element_remove",
|
|
53
|
+
command: "motion.removeElement",
|
|
54
|
+
description: "Deletes one or more elements. Deleting a group removes its children too.",
|
|
55
|
+
inputSchema: schema({
|
|
56
|
+
id: S.string("Element ID"),
|
|
57
|
+
ids: S.array("Several element IDs", { type: "string" }),
|
|
58
|
+
}),
|
|
59
|
+
}),
|
|
60
|
+
|
|
61
|
+
bridgeTool({
|
|
62
|
+
name: "creavit_motion_element_arrange",
|
|
63
|
+
command: "motion.arrangeElements",
|
|
64
|
+
description:
|
|
65
|
+
"Structural element operations: duplicate (ids), group (2+ ids sharing a parent), ungroup (id), reorder (id + targetId + position), moveInto (id + groupId).",
|
|
66
|
+
inputSchema: schema(
|
|
67
|
+
{
|
|
68
|
+
action: S.string("duplicate, group, ungroup, reorder or moveInto", {
|
|
69
|
+
enum: ["duplicate", "group", "ungroup", "reorder", "moveInto"],
|
|
70
|
+
}),
|
|
71
|
+
ids: S.array("Element IDs (duplicate, group)", { type: "string" }),
|
|
72
|
+
id: S.string("Element ID (ungroup, reorder, moveInto source)"),
|
|
73
|
+
targetId: S.string("Reference element for reorder"),
|
|
74
|
+
position: S.string("before or after (reorder)", { enum: ["before", "after"] }),
|
|
75
|
+
groupId: S.string("Target group for moveInto"),
|
|
76
|
+
},
|
|
77
|
+
["action"],
|
|
78
|
+
),
|
|
79
|
+
}),
|
|
80
|
+
|
|
81
|
+
bridgeTool({
|
|
82
|
+
name: "creavit_motion_select",
|
|
83
|
+
command: "motion.select",
|
|
84
|
+
description:
|
|
85
|
+
"Sets the Motion Studio selection. Mostly cosmetic for an agent — the element tools take explicit ids — but useful to show the user what you changed.",
|
|
86
|
+
inputSchema: schema({
|
|
87
|
+
id: S.string("Element ID"),
|
|
88
|
+
ids: S.array("Several element IDs", { type: "string" }),
|
|
89
|
+
clear: S.bool("Clear the selection"),
|
|
90
|
+
frame: S.bool("Select the scene frame"),
|
|
91
|
+
}),
|
|
92
|
+
}),
|
|
93
|
+
|
|
94
|
+
bridgeTool({
|
|
95
|
+
name: "creavit_motion_presets",
|
|
96
|
+
command: "motion.listPresets",
|
|
97
|
+
description:
|
|
98
|
+
"Lists the animation preset catalog — in (entrances), out (exits), custom and effects — plus the raw action types and easing names. Read this BEFORE adding animations; preset ids like 'slide-in-up' or 'blur-scale-in' produce the polished multi-action results.",
|
|
99
|
+
inputSchema: schema({
|
|
100
|
+
tab: S.string("in, out, custom or effects (omit for all)", {
|
|
101
|
+
enum: ["in", "out", "custom", "effects"],
|
|
102
|
+
}),
|
|
103
|
+
}),
|
|
104
|
+
}),
|
|
105
|
+
|
|
106
|
+
bridgeTool({
|
|
107
|
+
name: "creavit_motion_action_add",
|
|
108
|
+
command: "motion.addAction",
|
|
109
|
+
description:
|
|
110
|
+
"Animates an element. Preferred: pass `presetId` from creavit_motion_presets. For manual control pass `type` (fade, slide, scale, rotate, blur, pop, bounce, reveal, typewriter, move, maskMove) with `direction`, `duration`, `easing` and type specific `params`. `start` defaults to the playhead; the scene duration is extended to fit.",
|
|
111
|
+
inputSchema: schema(
|
|
112
|
+
{
|
|
113
|
+
elementId: S.string("Element to animate"),
|
|
114
|
+
presetId: S.string("Preset id from creavit_motion_presets"),
|
|
115
|
+
type: S.string("Raw action type when no preset is used"),
|
|
116
|
+
direction: S.string("in or out", { enum: ["in", "out"] }),
|
|
117
|
+
start: S.number("Start time in seconds (defaults to the playhead)"),
|
|
118
|
+
duration: S.number("Duration in seconds"),
|
|
119
|
+
easing: S.string("Easing name from creavit_motion_presets"),
|
|
120
|
+
params: S.object("Type specific params: distance, axis, angle, startOffset, moveX, moveY..."),
|
|
121
|
+
},
|
|
122
|
+
["elementId"],
|
|
123
|
+
),
|
|
124
|
+
mapResult: (result) =>
|
|
125
|
+
textResult({ ...result, note: "Verify the result with creavit_motion_screenshot at a few times." }),
|
|
126
|
+
}),
|
|
127
|
+
|
|
128
|
+
bridgeTool({
|
|
129
|
+
name: "creavit_motion_action_update",
|
|
130
|
+
command: "motion.updateAction",
|
|
131
|
+
description:
|
|
132
|
+
"Updates one animation action: start, duration, easing, direction or params. Get action ids from creavit_motion_element_get.",
|
|
133
|
+
inputSchema: schema(
|
|
134
|
+
{
|
|
135
|
+
elementId: S.string("Element ID"),
|
|
136
|
+
actionId: S.string("Action ID"),
|
|
137
|
+
patch: S.object("Fields to change: start, duration, easing, direction, params"),
|
|
138
|
+
},
|
|
139
|
+
["elementId", "actionId", "patch"],
|
|
140
|
+
),
|
|
141
|
+
}),
|
|
142
|
+
|
|
143
|
+
bridgeTool({
|
|
144
|
+
name: "creavit_motion_action_remove",
|
|
145
|
+
command: "motion.removeAction",
|
|
146
|
+
description: "Deletes one animation action from an element, or every action with all=true.",
|
|
147
|
+
inputSchema: schema(
|
|
148
|
+
{
|
|
149
|
+
elementId: S.string("Element ID"),
|
|
150
|
+
actionId: S.string("Action ID"),
|
|
151
|
+
all: S.bool("Delete every action on this element"),
|
|
152
|
+
},
|
|
153
|
+
["elementId"],
|
|
154
|
+
),
|
|
155
|
+
}),
|
|
156
|
+
];
|
|
157
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// MCP araçları — Motion Studio oturumu: açma/kapama, sahne, oynatma, kare.
|
|
2
|
+
|
|
3
|
+
import { bridgeTool, schema, S, textResult } from "../defineTool.mjs";
|
|
4
|
+
import { callCommand } from "../../bridgeClient.mjs";
|
|
5
|
+
|
|
6
|
+
export function motionSessionTools() {
|
|
7
|
+
return [
|
|
8
|
+
bridgeTool({
|
|
9
|
+
name: "creavit_motion_state",
|
|
10
|
+
command: "motion.getState",
|
|
11
|
+
description:
|
|
12
|
+
"Live Motion Studio state: is it open, scene name/size/fps, duration, playhead, element count and timeline motion segment count. Call this FIRST for any motion work — most other motion tools need Motion Studio to be open.",
|
|
13
|
+
inputSchema: schema(),
|
|
14
|
+
}),
|
|
15
|
+
|
|
16
|
+
bridgeTool({
|
|
17
|
+
name: "creavit_motion_open",
|
|
18
|
+
command: "motion.open",
|
|
19
|
+
description:
|
|
20
|
+
"Opens Motion Studio inside the editor window. Pass `segmentId` for an existing timeline motion segment (see creavit_motion_segments), `libraryMotionId` for a saved motion, or new=true to start a fresh scene — with `startTime` it also creates a timeline segment there. With no arguments it resumes the previous session.",
|
|
21
|
+
inputSchema: schema({
|
|
22
|
+
segmentId: S.string("Timeline motion segment ID"),
|
|
23
|
+
libraryMotionId: S.string("Saved library motion ID"),
|
|
24
|
+
new: S.bool("Start a new scene"),
|
|
25
|
+
startTime: S.number("With new=true: place the segment at this time (seconds)"),
|
|
26
|
+
duration: S.number("Scene duration in seconds"),
|
|
27
|
+
name: S.string("Scene name"),
|
|
28
|
+
}),
|
|
29
|
+
}),
|
|
30
|
+
|
|
31
|
+
bridgeTool({
|
|
32
|
+
name: "creavit_motion_save",
|
|
33
|
+
command: "motion.save",
|
|
34
|
+
description:
|
|
35
|
+
"Writes the scene back to its timeline segment (or library motion) while staying in Motion Studio. Call creavit_project_save afterwards to persist the project file.",
|
|
36
|
+
inputSchema: schema(),
|
|
37
|
+
mapResult: (result) =>
|
|
38
|
+
textResult({ ...result, note: "Saved into the segment. Call creavit_project_save to persist." }),
|
|
39
|
+
}),
|
|
40
|
+
|
|
41
|
+
bridgeTool({
|
|
42
|
+
name: "creavit_motion_close",
|
|
43
|
+
command: "motion.close",
|
|
44
|
+
description:
|
|
45
|
+
"Leaves Motion Studio and returns to the video editor. Saves the scene by default; pass save=false to discard.",
|
|
46
|
+
inputSchema: schema({ save: S.bool("Save before leaving (default true)") }),
|
|
47
|
+
}),
|
|
48
|
+
|
|
49
|
+
bridgeTool({
|
|
50
|
+
name: "creavit_motion_scene_get",
|
|
51
|
+
command: "motion.getScene",
|
|
52
|
+
description:
|
|
53
|
+
"Reads the scene: settings (size, fps, background, frame offset) plus element summaries. Pass full=true for the COMPLETE element tree with every animation action — that output can be large.",
|
|
54
|
+
inputSchema: schema({ full: S.bool("Include the complete element tree with actions") }),
|
|
55
|
+
}),
|
|
56
|
+
|
|
57
|
+
bridgeTool({
|
|
58
|
+
name: "creavit_motion_scene_set",
|
|
59
|
+
command: "motion.setScene",
|
|
60
|
+
description:
|
|
61
|
+
"Updates scene settings. background 'transparent' keeps the scene see-through over the video. Duration is clamped to fit the animation content.",
|
|
62
|
+
inputSchema: schema({
|
|
63
|
+
width: S.number("Scene width in px"),
|
|
64
|
+
height: S.number("Scene height in px"),
|
|
65
|
+
fps: S.number("Frame rate (default 60)"),
|
|
66
|
+
background: S.string("'transparent' or a CSS color"),
|
|
67
|
+
workspaceBackground: S.string("Editor workspace background color"),
|
|
68
|
+
frameOffset: S.object("Frame offset from the viewport center: {x, y}"),
|
|
69
|
+
name: S.string("Scene name"),
|
|
70
|
+
duration: S.number("Scene duration in seconds"),
|
|
71
|
+
}),
|
|
72
|
+
}),
|
|
73
|
+
|
|
74
|
+
bridgeTool({
|
|
75
|
+
name: "creavit_motion_playback",
|
|
76
|
+
command: "motion.playback",
|
|
77
|
+
description:
|
|
78
|
+
"Controls Motion Studio preview playback. Use action='seek' with `time` to move the playhead — new actions are added at the playhead.",
|
|
79
|
+
inputSchema: schema(
|
|
80
|
+
{
|
|
81
|
+
action: S.string("play, pause, toggle, seek or loop", {
|
|
82
|
+
enum: ["play", "pause", "toggle", "seek", "loop"],
|
|
83
|
+
}),
|
|
84
|
+
time: S.number("Target time in seconds (seek)"),
|
|
85
|
+
loop: S.bool("Loop on/off"),
|
|
86
|
+
},
|
|
87
|
+
["action"],
|
|
88
|
+
),
|
|
89
|
+
}),
|
|
90
|
+
|
|
91
|
+
bridgeTool({
|
|
92
|
+
name: "creavit_motion_screenshot",
|
|
93
|
+
command: "motion.screenshot",
|
|
94
|
+
description:
|
|
95
|
+
"Renders the motion scene at a given time and returns it as a PNG image. Use this to VERIFY what an animation actually looks like — check a few times across the duration after editing.",
|
|
96
|
+
inputSchema: schema({
|
|
97
|
+
time: S.number("Time in seconds (defaults to the playhead)"),
|
|
98
|
+
scale: S.number("Render scale (default 1)"),
|
|
99
|
+
maxWidth: S.number("Maximum output width in px (default 1600)"),
|
|
100
|
+
}),
|
|
101
|
+
timeoutMs: 120_000,
|
|
102
|
+
mapResult: (result) => ({
|
|
103
|
+
content: [
|
|
104
|
+
{ type: "image", data: result.base64, mimeType: result.mimeType || "image/png" },
|
|
105
|
+
{ type: "text", text: `Motion frame @ ${Number(result.atTime || 0).toFixed(2)}s` },
|
|
106
|
+
],
|
|
107
|
+
}),
|
|
108
|
+
}),
|
|
109
|
+
|
|
110
|
+
{
|
|
111
|
+
name: "creavit_motion_history",
|
|
112
|
+
description: "Undoes the last Motion Studio change, or redoes it.",
|
|
113
|
+
inputSchema: schema(
|
|
114
|
+
{ action: S.string("undo or redo", { enum: ["undo", "redo"] }) },
|
|
115
|
+
["action"],
|
|
116
|
+
),
|
|
117
|
+
run: async ({ action }) => {
|
|
118
|
+
if (action !== "undo" && action !== "redo") {
|
|
119
|
+
throw new Error("`action` must be either 'undo' or 'redo'");
|
|
120
|
+
}
|
|
121
|
+
return textResult(await callCommand("motion.history", { action }));
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
bridgeTool({
|
|
126
|
+
name: "creavit_motion_export",
|
|
127
|
+
command: "motion.export",
|
|
128
|
+
description:
|
|
129
|
+
"Exports the motion scene. Formats: video (mp4), gif, json, lottie, html (zip). Video/GIF rendering takes minutes and the file is written to the Downloads folder; follow progress with creavit_events (motion.export.started / finished / failed).",
|
|
130
|
+
inputSchema: schema({
|
|
131
|
+
format: S.string("video, gif, json, lottie or html", {
|
|
132
|
+
enum: ["video", "gif", "json", "lottie", "html"],
|
|
133
|
+
}),
|
|
134
|
+
scale: S.number("Render scale for video/gif: 0.5, 1, 1.5 or 2"),
|
|
135
|
+
}),
|
|
136
|
+
timeoutMs: 1_800_000,
|
|
137
|
+
}),
|
|
138
|
+
|
|
139
|
+
bridgeTool({
|
|
140
|
+
name: "creavit_motion_import",
|
|
141
|
+
command: "motion.import",
|
|
142
|
+
description:
|
|
143
|
+
"Adds elements from an exported motion JSON / Lottie payload into the open scene. Pass the parsed object as `payload` or raw text as `json`.",
|
|
144
|
+
inputSchema: schema({
|
|
145
|
+
payload: S.object("Motion JSON payload object"),
|
|
146
|
+
json: S.string("Raw JSON text"),
|
|
147
|
+
}),
|
|
148
|
+
timeoutMs: 120_000,
|
|
149
|
+
}),
|
|
150
|
+
];
|
|
151
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// MCP araçları — ana timeline'daki motion segmentleri, kütüphane ve şablonlar.
|
|
2
|
+
|
|
3
|
+
import { bridgeTool, schema, S } from "../defineTool.mjs";
|
|
4
|
+
|
|
5
|
+
export function motionTimelineTools() {
|
|
6
|
+
return [
|
|
7
|
+
bridgeTool({
|
|
8
|
+
name: "creavit_motion_segments",
|
|
9
|
+
command: "motion.segments",
|
|
10
|
+
description:
|
|
11
|
+
"Motion segments on the MAIN editor timeline (the overlays composited on top of the video): action='list' to read them, 'add' to place a new one (opens Motion Studio unless open=false), 'update' to move/resize/transform one, 'remove' to delete. Works with Motion Studio closed.",
|
|
12
|
+
inputSchema: schema({
|
|
13
|
+
action: S.string("list, add, update or remove (default list)", {
|
|
14
|
+
enum: ["list", "add", "update", "remove"],
|
|
15
|
+
}),
|
|
16
|
+
id: S.string("Segment ID (update, remove)"),
|
|
17
|
+
startTime: S.number("Timeline position in seconds (add)"),
|
|
18
|
+
duration: S.number("Duration in seconds (add)"),
|
|
19
|
+
name: S.string("Segment name (add)"),
|
|
20
|
+
open: S.bool("Open Motion Studio on the new segment (default true)"),
|
|
21
|
+
patch: S.object("Update fields: startTime, duration, name, position, scale, rotation, opacity"),
|
|
22
|
+
}),
|
|
23
|
+
}),
|
|
24
|
+
|
|
25
|
+
bridgeTool({
|
|
26
|
+
name: "creavit_motion_library",
|
|
27
|
+
command: "motion.library",
|
|
28
|
+
description:
|
|
29
|
+
"Reusable motion library: action='list' saved motions, 'save' the open scene into it, 'rename', 'remove', or 'addToTimeline' to drop a saved motion onto the video timeline at `startTime`.",
|
|
30
|
+
inputSchema: schema({
|
|
31
|
+
action: S.string("list, save, rename, remove or addToTimeline (default list)", {
|
|
32
|
+
enum: ["list", "save", "rename", "remove", "addToTimeline"],
|
|
33
|
+
}),
|
|
34
|
+
id: S.string("Library motion ID"),
|
|
35
|
+
name: S.string("Name (save, rename)"),
|
|
36
|
+
startTime: S.number("Timeline position in seconds (addToTimeline)"),
|
|
37
|
+
}),
|
|
38
|
+
}),
|
|
39
|
+
|
|
40
|
+
bridgeTool({
|
|
41
|
+
name: "creavit_motion_templates",
|
|
42
|
+
command: "motion.templates",
|
|
43
|
+
description:
|
|
44
|
+
"Online motion template gallery: action='list' (optionally filtered by `category` or `search`) to browse ready-made animations, action='apply' with `templateId` to add one into the open scene. Applying needs Motion Studio to be open.",
|
|
45
|
+
inputSchema: schema({
|
|
46
|
+
action: S.string("list or apply (default list)", { enum: ["list", "apply"] }),
|
|
47
|
+
templateId: S.string("Template ID (apply)"),
|
|
48
|
+
category: S.string("Category filter (list)"),
|
|
49
|
+
search: S.string("Text search across name, description and tags (list)"),
|
|
50
|
+
}),
|
|
51
|
+
timeoutMs: 60_000,
|
|
52
|
+
}),
|
|
53
|
+
];
|
|
54
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// MCP araçları — Motion Studio.
|
|
2
|
+
// Motion Studio editör penceresi içinde bir moddur: önce creavit_project_open ile
|
|
3
|
+
// editör açılır, sonra creavit_motion_open ile motion moduna girilir.
|
|
4
|
+
|
|
5
|
+
import { motionSessionTools } from "./motion/sessionTools.mjs";
|
|
6
|
+
import { motionElementTools } from "./motion/elementTools.mjs";
|
|
7
|
+
import { motionTimelineTools } from "./motion/timelineTools.mjs";
|
|
8
|
+
|
|
9
|
+
export function motionTools() {
|
|
10
|
+
return [...motionSessionTools(), ...motionElementTools(), ...motionTimelineTools()];
|
|
11
|
+
}
|
|
@@ -1,10 +1,38 @@
|
|
|
1
1
|
// MCP araçları — uygulama durumu, kayıt akışı, cihazlar ve olay akışı.
|
|
2
2
|
|
|
3
3
|
import { bridgeTool, schema, S, textResult } from "./defineTool.mjs";
|
|
4
|
-
import { callCommand } from "../bridgeClient.mjs";
|
|
4
|
+
import { callCommand, isAppRunning } from "../bridgeClient.mjs";
|
|
5
|
+
import {
|
|
6
|
+
ensureAppRunning,
|
|
7
|
+
resolveAppPath,
|
|
8
|
+
DEFAULT_LAUNCH_TIMEOUT_MS,
|
|
9
|
+
} from "../appLauncher.mjs";
|
|
5
10
|
|
|
6
11
|
export function systemTools() {
|
|
7
12
|
return [
|
|
13
|
+
{
|
|
14
|
+
name: "creavit_app_launch",
|
|
15
|
+
description:
|
|
16
|
+
"Starts Creavit Studio if it is not already running, then waits until its agent bridge is ready. Looks for the app in /Applications and ~/Applications (override with CREAVIT_APP_PATH). Other tools also auto-launch on first use, so call this only when you want to start the app explicitly or check where it was found.",
|
|
17
|
+
inputSchema: schema({
|
|
18
|
+
timeoutMs: S.number(
|
|
19
|
+
`How long to wait for the bridge after launching (default ${DEFAULT_LAUNCH_TIMEOUT_MS})`,
|
|
20
|
+
),
|
|
21
|
+
}),
|
|
22
|
+
run: async (args) => {
|
|
23
|
+
const appPath = resolveAppPath();
|
|
24
|
+
const { launched } = await ensureAppRunning({
|
|
25
|
+
isRunning: isAppRunning,
|
|
26
|
+
timeoutMs: args?.timeoutMs || DEFAULT_LAUNCH_TIMEOUT_MS,
|
|
27
|
+
});
|
|
28
|
+
return textResult({
|
|
29
|
+
launched,
|
|
30
|
+
alreadyRunning: !launched,
|
|
31
|
+
appPath,
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
|
|
8
36
|
bridgeTool({
|
|
9
37
|
name: "creavit_app_info",
|
|
10
38
|
description:
|
|
@@ -49,7 +77,7 @@ export function systemTools() {
|
|
|
49
77
|
"Starts a screen recording. Get source IDs from creavit_devices_list first. Monitor with creavit_recording_status, and finish with creavit_recording_stop.",
|
|
50
78
|
inputSchema: schema({
|
|
51
79
|
options: S.object(
|
|
52
|
-
"Recording options: {sourceType:'display'|'window'|'area', sourceId, cameraEnabled, micEnabled, systemAudioEnabled, delayMs, area:{x,y,width,height}}",
|
|
80
|
+
"Recording options: {sourceType:'display'|'window'|'area', sourceId, cameraEnabled, micEnabled, systemAudioEnabled, delayMs, area:{x,y,width,height}}. cameraEnabled:false also turns the camera off and hides its window, so it does not appear in a screen recording; cameraEnabled:true opens and starts it.",
|
|
53
81
|
),
|
|
54
82
|
}),
|
|
55
83
|
timeoutMs: 180_000,
|