@excalimate/mcp-server 0.3.5 → 0.4.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/dist/httpServer.d.ts.map +1 -1
- package/dist/httpServer.js +4 -3
- package/dist/httpServer.js.map +1 -1
- package/dist/index.js +10 -5
- package/dist/index.js.map +1 -1
- package/dist/server/animationTools.d.ts.map +1 -1
- package/dist/server/animationTools.js +43 -63
- package/dist/server/animationTools.js.map +1 -1
- package/dist/server/compositeTools.d.ts +18 -0
- package/dist/server/compositeTools.d.ts.map +1 -0
- package/dist/server/compositeTools.js +209 -0
- package/dist/server/compositeTools.js.map +1 -0
- package/dist/server/referenceText.d.ts +2 -2
- package/dist/server/referenceText.d.ts.map +1 -1
- package/dist/server/referenceText.js +83 -254
- package/dist/server/referenceText.js.map +1 -1
- package/dist/server/sceneTools.d.ts.map +1 -1
- package/dist/server/sceneTools.js +2 -1
- package/dist/server/sceneTools.js.map +1 -1
- package/dist/server/stateContext.d.ts +36 -1
- package/dist/server/stateContext.d.ts.map +1 -1
- package/dist/server/stateContext.js +157 -13
- package/dist/server/stateContext.js.map +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +4 -2
- package/dist/server.js.map +1 -1
- package/dist/state.d.ts +14 -0
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +57 -0
- package/dist/state.js.map +1 -1
- package/package.json +4 -2
|
@@ -1,7 +1,127 @@
|
|
|
1
1
|
import { createDefaultState } from '../state.js';
|
|
2
2
|
let _activeState = createDefaultState();
|
|
3
3
|
let _activeServerId = null;
|
|
4
|
+
let _stateVersion = 0;
|
|
4
5
|
export function getSharedState() { return _activeState; }
|
|
6
|
+
/**
|
|
7
|
+
* Cached JSON serialization of state areas.
|
|
8
|
+
* Invalidated by version counter — avoids re-serializing unchanged state
|
|
9
|
+
* on repeated get_scene / get_timeline / /state calls.
|
|
10
|
+
*/
|
|
11
|
+
const _jsonCache = {
|
|
12
|
+
fullState: { version: -1, json: '' },
|
|
13
|
+
sceneElements: { version: -1, json: '' },
|
|
14
|
+
timeline: { version: -1, json: '' },
|
|
15
|
+
};
|
|
16
|
+
/** Get the full state as a JSON string, using cache when unchanged. */
|
|
17
|
+
export function getSharedStateJSON() {
|
|
18
|
+
if (_jsonCache.fullState.version === _stateVersion)
|
|
19
|
+
return _jsonCache.fullState.json;
|
|
20
|
+
const json = JSON.stringify(_activeState);
|
|
21
|
+
_jsonCache.fullState = { version: _stateVersion, json };
|
|
22
|
+
return json;
|
|
23
|
+
}
|
|
24
|
+
/** Get scene elements as a pretty JSON string, using cache when unchanged. */
|
|
25
|
+
export function getSceneElementsJSON() {
|
|
26
|
+
if (_jsonCache.sceneElements.version === _stateVersion)
|
|
27
|
+
return _jsonCache.sceneElements.json;
|
|
28
|
+
const json = JSON.stringify(_activeState.scene.elements, null, 2);
|
|
29
|
+
_jsonCache.sceneElements = { version: _stateVersion, json };
|
|
30
|
+
return json;
|
|
31
|
+
}
|
|
32
|
+
/** Get timeline + clip + camera as a pretty JSON string, using cache when unchanged. */
|
|
33
|
+
export function getTimelineJSON() {
|
|
34
|
+
if (_jsonCache.timeline.version === _stateVersion)
|
|
35
|
+
return _jsonCache.timeline.json;
|
|
36
|
+
const json = JSON.stringify({
|
|
37
|
+
timeline: _activeState.timeline,
|
|
38
|
+
clipStart: _activeState.clipStart,
|
|
39
|
+
clipEnd: _activeState.clipEnd,
|
|
40
|
+
cameraFrame: _activeState.cameraFrame,
|
|
41
|
+
}, null, 2);
|
|
42
|
+
_jsonCache.timeline = { version: _stateVersion, json };
|
|
43
|
+
return json;
|
|
44
|
+
}
|
|
45
|
+
// ── Delta computation helpers ──────────────────────────────────
|
|
46
|
+
/** Snapshot the minimal data needed to compute scene deltas. */
|
|
47
|
+
function snapshotElementIds(state) {
|
|
48
|
+
const map = new Map();
|
|
49
|
+
for (const el of state.scene.elements) {
|
|
50
|
+
// Use version (or versionNonce) as a change indicator
|
|
51
|
+
map.set(el.id, el.version ?? 0);
|
|
52
|
+
}
|
|
53
|
+
return map;
|
|
54
|
+
}
|
|
55
|
+
/** Snapshot track IDs and their keyframe counts for change detection. */
|
|
56
|
+
function snapshotTracks(state) {
|
|
57
|
+
const map = new Map();
|
|
58
|
+
for (const t of state.timeline.tracks) {
|
|
59
|
+
map.set(t.id, t.keyframes.length);
|
|
60
|
+
}
|
|
61
|
+
return map;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Properties stripped from elements in SSE deltas to reduce payload size.
|
|
65
|
+
* These are non-visual metadata that the client can re-fetch on reconnect
|
|
66
|
+
* via the /state endpoint (which sends full elements).
|
|
67
|
+
*/
|
|
68
|
+
const STRIP_ELEMENT_KEYS = new Set([
|
|
69
|
+
'seed', 'versionNonce', 'updated', 'link', 'locked',
|
|
70
|
+
'roundness', 'boundElements', 'lastCommittedPoint',
|
|
71
|
+
'startBinding', 'endBinding', 'originalText', 'autoResize', 'baseline',
|
|
72
|
+
]);
|
|
73
|
+
function stripElement(el) {
|
|
74
|
+
const stripped = {};
|
|
75
|
+
for (const key of Object.keys(el)) {
|
|
76
|
+
if (!STRIP_ELEMENT_KEYS.has(key))
|
|
77
|
+
stripped[key] = el[key];
|
|
78
|
+
}
|
|
79
|
+
return stripped;
|
|
80
|
+
}
|
|
81
|
+
function computeSceneDelta(prevElements, current) {
|
|
82
|
+
const upsert = [];
|
|
83
|
+
const currentIds = new Set();
|
|
84
|
+
for (const el of current.scene.elements) {
|
|
85
|
+
currentIds.add(el.id);
|
|
86
|
+
const prevVersion = prevElements.get(el.id);
|
|
87
|
+
if (prevVersion === undefined || prevVersion !== (el.version ?? 0)) {
|
|
88
|
+
upsert.push(stripElement(el));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const removed = [];
|
|
92
|
+
for (const id of prevElements.keys()) {
|
|
93
|
+
if (!currentIds.has(id))
|
|
94
|
+
removed.push(id);
|
|
95
|
+
}
|
|
96
|
+
if (upsert.length === 0 && removed.length === 0)
|
|
97
|
+
return undefined;
|
|
98
|
+
return { upsert, removed };
|
|
99
|
+
}
|
|
100
|
+
function computeTimelineDelta(prevTracks, prevDuration, prevFps, current) {
|
|
101
|
+
const upsertedTracks = [];
|
|
102
|
+
const currentTrackIds = new Set();
|
|
103
|
+
for (const track of current.timeline.tracks) {
|
|
104
|
+
currentTrackIds.add(track.id);
|
|
105
|
+
const prevKfCount = prevTracks.get(track.id);
|
|
106
|
+
if (prevKfCount === undefined || prevKfCount !== track.keyframes.length) {
|
|
107
|
+
upsertedTracks.push(track);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const removedTrackIds = [];
|
|
111
|
+
for (const id of prevTracks.keys()) {
|
|
112
|
+
if (!currentTrackIds.has(id))
|
|
113
|
+
removedTrackIds.push(id);
|
|
114
|
+
}
|
|
115
|
+
const metaChanged = current.timeline.duration !== prevDuration || current.timeline.fps !== prevFps;
|
|
116
|
+
if (upsertedTracks.length === 0 && removedTrackIds.length === 0 && !metaChanged)
|
|
117
|
+
return undefined;
|
|
118
|
+
const result = { upsertedTracks, removedTrackIds };
|
|
119
|
+
if (metaChanged) {
|
|
120
|
+
result.meta = { duration: current.timeline.duration, fps: current.timeline.fps };
|
|
121
|
+
}
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
// ── State context factory ──────────────────────────────────────
|
|
5
125
|
export function createStateContext(serverId, server, onStateChange) {
|
|
6
126
|
if (_activeServerId !== null) {
|
|
7
127
|
console.warn(`[excalimate] New server ${serverId} replacing active server ${_activeServerId}. ` +
|
|
@@ -9,13 +129,13 @@ export function createStateContext(serverId, server, onStateChange) {
|
|
|
9
129
|
}
|
|
10
130
|
_activeServerId = serverId;
|
|
11
131
|
// ── Delta broadcasting with debounce ───────────────────────────
|
|
12
|
-
// Track which top-level state areas are dirty via flags set by tools.
|
|
13
|
-
// When the debounced emit fires, only serialize and broadcast the
|
|
14
|
-
// dirty fields. This avoids serializing the entire scene+timeline
|
|
15
|
-
// on every keyframe addition.
|
|
16
132
|
let _emitTimer = null;
|
|
17
133
|
const _dirty = { scene: false, timeline: false, clip: false, cameraFrame: false };
|
|
18
|
-
|
|
134
|
+
// Snapshots taken before each tool call for delta computation
|
|
135
|
+
let _prevElementSnapshot = snapshotElementIds(_activeState);
|
|
136
|
+
let _prevTrackSnapshot = snapshotTracks(_activeState);
|
|
137
|
+
let _prevDuration = _activeState.timeline.duration;
|
|
138
|
+
let _prevFps = _activeState.timeline.fps;
|
|
19
139
|
function markDirty(area) {
|
|
20
140
|
if (area === 'all') {
|
|
21
141
|
_dirty.scene = _dirty.timeline = _dirty.clip = _dirty.cameraFrame = true;
|
|
@@ -25,8 +145,6 @@ export function createStateContext(serverId, server, onStateChange) {
|
|
|
25
145
|
}
|
|
26
146
|
}
|
|
27
147
|
const emitChange = () => {
|
|
28
|
-
// Default: mark everything dirty (tools that don't specify get full broadcast).
|
|
29
|
-
// Specific tools can call markDirty() before emitChange() for fine-grained deltas.
|
|
30
148
|
if (!_dirty.scene && !_dirty.timeline && !_dirty.clip && !_dirty.cameraFrame) {
|
|
31
149
|
markDirty('all');
|
|
32
150
|
}
|
|
@@ -38,19 +156,33 @@ export function createStateContext(serverId, server, onStateChange) {
|
|
|
38
156
|
if (!onStateChange)
|
|
39
157
|
return;
|
|
40
158
|
const delta = {};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
159
|
+
let hasContent = false;
|
|
160
|
+
if (_dirty.scene) {
|
|
161
|
+
delta.scene = computeSceneDelta(_prevElementSnapshot, _activeState);
|
|
162
|
+
_prevElementSnapshot = snapshotElementIds(_activeState);
|
|
163
|
+
if (delta.scene)
|
|
164
|
+
hasContent = true;
|
|
165
|
+
}
|
|
166
|
+
if (_dirty.timeline) {
|
|
167
|
+
delta.timeline = computeTimelineDelta(_prevTrackSnapshot, _prevDuration, _prevFps, _activeState);
|
|
168
|
+
_prevTrackSnapshot = snapshotTracks(_activeState);
|
|
169
|
+
_prevDuration = _activeState.timeline.duration;
|
|
170
|
+
_prevFps = _activeState.timeline.fps;
|
|
171
|
+
if (delta.timeline)
|
|
172
|
+
hasContent = true;
|
|
173
|
+
}
|
|
45
174
|
if (_dirty.clip) {
|
|
46
175
|
delta.clipStart = _activeState.clipStart;
|
|
47
176
|
delta.clipEnd = _activeState.clipEnd;
|
|
177
|
+
hasContent = true;
|
|
48
178
|
}
|
|
49
|
-
if (_dirty.cameraFrame)
|
|
179
|
+
if (_dirty.cameraFrame) {
|
|
50
180
|
delta.cameraFrame = _activeState.cameraFrame;
|
|
181
|
+
hasContent = true;
|
|
182
|
+
}
|
|
51
183
|
// Reset dirty flags
|
|
52
184
|
_dirty.scene = _dirty.timeline = _dirty.clip = _dirty.cameraFrame = false;
|
|
53
|
-
if (
|
|
185
|
+
if (!hasContent)
|
|
54
186
|
return;
|
|
55
187
|
onStateChange(delta);
|
|
56
188
|
}
|
|
@@ -62,10 +194,22 @@ export function createStateContext(serverId, server, onStateChange) {
|
|
|
62
194
|
server.__getState = () => _activeState;
|
|
63
195
|
const updateState = (newState) => {
|
|
64
196
|
_activeState = newState;
|
|
197
|
+
_stateVersion++;
|
|
65
198
|
};
|
|
66
199
|
const mutatingTool = (name, description, schema, handler, dirtyAreas) => {
|
|
67
200
|
server.tool(name, description, schema, async (args) => {
|
|
201
|
+
// Snapshot before the tool mutates state
|
|
202
|
+
if (!dirtyAreas || dirtyAreas.includes('scene')) {
|
|
203
|
+
_prevElementSnapshot = snapshotElementIds(_activeState);
|
|
204
|
+
}
|
|
205
|
+
if (!dirtyAreas || dirtyAreas.includes('timeline')) {
|
|
206
|
+
_prevTrackSnapshot = snapshotTracks(_activeState);
|
|
207
|
+
_prevDuration = _activeState.timeline.duration;
|
|
208
|
+
_prevFps = _activeState.timeline.fps;
|
|
209
|
+
}
|
|
68
210
|
const result = await handler(args);
|
|
211
|
+
// Bump version after mutation — invalidates JSON cache
|
|
212
|
+
_stateVersion++;
|
|
69
213
|
if (dirtyAreas) {
|
|
70
214
|
for (const area of dirtyAreas)
|
|
71
215
|
markDirty(area);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stateContext.js","sourceRoot":"","sources":["../../src/server/stateContext.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"stateContext.js","sourceRoot":"","sources":["../../src/server/stateContext.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAgCjD,IAAI,YAAY,GAAgB,kBAAkB,EAAE,CAAC;AACrD,IAAI,eAAe,GAAkB,IAAI,CAAC;AAC1C,IAAI,aAAa,GAAG,CAAC,CAAC;AAEtB,MAAM,UAAU,cAAc,KAAkB,OAAO,YAAY,CAAC,CAAC,CAAC;AAEtE;;;;GAIG;AACH,MAAM,UAAU,GAAG;IACjB,SAAS,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;IACpC,aAAa,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;IACxC,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;CACpC,CAAC;AAEF,uEAAuE;AACvE,MAAM,UAAU,kBAAkB;IAChC,IAAI,UAAU,CAAC,SAAS,CAAC,OAAO,KAAK,aAAa;QAAE,OAAO,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC;IACrF,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAC1C,UAAU,CAAC,SAAS,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;IACxD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,oBAAoB;IAClC,IAAI,UAAU,CAAC,aAAa,CAAC,OAAO,KAAK,aAAa;QAAE,OAAO,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC;IAC7F,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAClE,UAAU,CAAC,aAAa,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;IAC5D,OAAO,IAAI,CAAC;AACd,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,eAAe;IAC7B,IAAI,UAAU,CAAC,QAAQ,CAAC,OAAO,KAAK,aAAa;QAAE,OAAO,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC;IACnF,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;QAC1B,QAAQ,EAAE,YAAY,CAAC,QAAQ;QAC/B,SAAS,EAAE,YAAY,CAAC,SAAS;QACjC,OAAO,EAAE,YAAY,CAAC,OAAO;QAC7B,WAAW,EAAE,YAAY,CAAC,WAAW;KACtC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACZ,UAAU,CAAC,QAAQ,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;IACvD,OAAO,IAAI,CAAC;AACd,CAAC;AAkBD,kEAAkE;AAElE,gEAAgE;AAChE,SAAS,kBAAkB,CAAC,KAAkB;IAC5C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QACtC,sDAAsD;QACtD,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,yEAAyE;AACzE,SAAS,cAAc,CAAC,KAAkB;IACxC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACtC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC;IACjC,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ;IACnD,WAAW,EAAE,eAAe,EAAE,oBAAoB;IAClD,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,UAAU;CACvE,CAAC,CAAC;AAEH,SAAS,YAAY,CAAC,EAAO;IAC3B,MAAM,QAAQ,GAAQ,EAAE,CAAC;IACzB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;QAClC,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,iBAAiB,CACxB,YAAiC,EACjC,OAAoB;IAEpB,MAAM,MAAM,GAAU,EAAE,CAAC;IACzB,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IAErC,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QACxC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACtB,MAAM,WAAW,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC5C,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC;YACnE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,EAAE,IAAI,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC;QACrC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAClE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC7B,CAAC;AAED,SAAS,oBAAoB,CAC3B,UAA+B,EAC/B,YAAoB,EACpB,OAAe,EACf,OAAoB;IAEpB,MAAM,cAAc,GAAU,EAAE,CAAC;IACjC,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAE1C,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC5C,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC9B,MAAM,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC7C,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;YACxE,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,KAAK,MAAM,EAAE,IAAI,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC;QACnC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,QAAQ,KAAK,YAAY,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,KAAK,OAAO,CAAC;IAEnG,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,WAAW;QAAE,OAAO,SAAS,CAAC;IAElG,MAAM,MAAM,GAA2B,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC;IAC3E,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,CAAC,IAAI,GAAG,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC;IACnF,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,kEAAkE;AAElE,MAAM,UAAU,kBAAkB,CAChC,QAAgB,EAChB,MAAiB,EACjB,aAAmC;IAEnC,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;QAC7B,OAAO,CAAC,IAAI,CACV,2BAA2B,QAAQ,4BAA4B,eAAe,IAAI;YAClF,sEAAsE,CACvE,CAAC;IACJ,CAAC;IACD,eAAe,GAAG,QAAQ,CAAC;IAE3B,kEAAkE;IAClE,IAAI,UAAU,GAAyC,IAAI,CAAC;IAC5D,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;IAElF,8DAA8D;IAC9D,IAAI,oBAAoB,GAAwB,kBAAkB,CAAC,YAAY,CAAC,CAAC;IACjF,IAAI,kBAAkB,GAAwB,cAAc,CAAC,YAAY,CAAC,CAAC;IAC3E,IAAI,aAAa,GAAW,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAC3D,IAAI,QAAQ,GAAW,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC;IAEjD,SAAS,SAAS,CAAC,IAA2D;QAC5E,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YACnB,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC;QAC3E,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QACtB,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,GAAG,EAAE;QACtB,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YAC7E,SAAS,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;QAED,IAAI,UAAU;YAAE,YAAY,CAAC,UAAU,CAAC,CAAC;QACzC,UAAU,GAAG,UAAU,CAAC,GAAG,EAAE;YAC3B,UAAU,GAAG,IAAI,CAAC;YAClB,IAAI,CAAC;gBACH,IAAI,CAAC,aAAa;oBAAE,OAAO;gBAE3B,MAAM,KAAK,GAAe,EAAE,CAAC;gBAC7B,IAAI,UAAU,GAAG,KAAK,CAAC;gBAEvB,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;oBACjB,KAAK,CAAC,KAAK,GAAG,iBAAiB,CAAC,oBAAoB,EAAE,YAAY,CAAC,CAAC;oBACpE,oBAAoB,GAAG,kBAAkB,CAAC,YAAY,CAAC,CAAC;oBACxD,IAAI,KAAK,CAAC,KAAK;wBAAE,UAAU,GAAG,IAAI,CAAC;gBACrC,CAAC;gBACD,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;oBACpB,KAAK,CAAC,QAAQ,GAAG,oBAAoB,CAAC,kBAAkB,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;oBACjG,kBAAkB,GAAG,cAAc,CAAC,YAAY,CAAC,CAAC;oBAClD,aAAa,GAAG,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC;oBAC/C,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC;oBACrC,IAAI,KAAK,CAAC,QAAQ;wBAAE,UAAU,GAAG,IAAI,CAAC;gBACxC,CAAC;gBACD,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;oBAChB,KAAK,CAAC,SAAS,GAAG,YAAY,CAAC,SAAS,CAAC;oBACzC,KAAK,CAAC,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC;oBACrC,UAAU,GAAG,IAAI,CAAC;gBACpB,CAAC;gBACD,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;oBACvB,KAAK,CAAC,WAAW,GAAG,YAAY,CAAC,WAAW,CAAC;oBAC7C,UAAU,GAAG,IAAI,CAAC;gBACpB,CAAC;gBAED,oBAAoB;gBACpB,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,WAAW,GAAG,KAAK,CAAC;gBAE1E,IAAI,CAAC,UAAU;oBAAE,OAAO;gBACxB,aAAa,CAAC,KAAK,CAAC,CAAC;YACvB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC,EAAE,EAAE,CAAC,CAAC;IACT,CAAC,CAAC;IAED,MAAc,CAAC,UAAU,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC;IAEhD,MAAM,WAAW,GAAG,CAAC,QAAqB,EAAE,EAAE;QAC5C,YAAY,GAAG,QAAQ,CAAC;QACxB,aAAa,EAAE,CAAC;IAClB,CAAC,CAAC;IAEF,MAAM,YAAY,GAAiC,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE;QACpG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,IAAS,EAAE,EAAE;YACzD,yCAAyC;YACzC,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAChD,oBAAoB,GAAG,kBAAkB,CAAC,YAAY,CAAC,CAAC;YAC1D,CAAC;YACD,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBACnD,kBAAkB,GAAG,cAAc,CAAC,YAAY,CAAC,CAAC;gBAClD,aAAa,GAAG,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBAC/C,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC;YACvC,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;YACnC,uDAAuD;YACvD,aAAa,EAAE,CAAC;YAChB,IAAI,UAAU,EAAE,CAAC;gBACf,KAAK,MAAM,IAAI,IAAI,UAAU;oBAAE,SAAS,CAAC,IAAI,CAAC,CAAC;YACjD,CAAC;YACD,UAAU,EAAE,CAAC;YACb,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,OAAO;QACL,QAAQ,EAAE,GAAG,EAAE,CAAC,YAAY;QAC5B,WAAW;QACX,UAAU;QACV,SAAS;QACT,YAAY;KACb,CAAC;AACJ,CAAC"}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import type { CheckpointStore } from './checkpoint-store.js';
|
|
3
|
-
import { getSharedState } from './server/stateContext.js';
|
|
3
|
+
import { getSharedState, getSharedStateJSON, getSceneElementsJSON, getTimelineJSON } from './server/stateContext.js';
|
|
4
4
|
import type { StateChangeListener } from './server/stateContext.js';
|
|
5
|
-
export { getSharedState };
|
|
5
|
+
export { getSharedState, getSharedStateJSON, getSceneElementsJSON, getTimelineJSON };
|
|
6
6
|
export type { StateChangeListener } from './server/stateContext.js';
|
|
7
7
|
export declare function createServer(store: CheckpointStore, onStateChange?: StateChangeListener): McpServer;
|
|
8
8
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAc7D,OAAO,EAAsB,cAAc,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACzI,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,eAAe,EAAE,CAAC;AACrF,YAAY,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,wBAAgB,YAAY,CAC1B,KAAK,EAAE,eAAe,EACtB,aAAa,CAAC,EAAE,mBAAmB,GAClC,SAAS,CA0BX"}
|
package/dist/server.js
CHANGED
|
@@ -8,12 +8,13 @@ import { getElementBounds } from './server/geometry.js';
|
|
|
8
8
|
import * as geometry from './server/geometry.js';
|
|
9
9
|
import { registerAnimationTools } from './server/animationTools.js';
|
|
10
10
|
import { registerCheckpointTools } from './server/checkpointTools.js';
|
|
11
|
+
import { registerCompositeTools } from './server/compositeTools.js';
|
|
11
12
|
import { registerQueryTools } from './server/queryTools.js';
|
|
12
13
|
import { registerShareTools } from './server/shareTools.js';
|
|
13
14
|
import { REFERENCE_TEXT, EXAMPLES_TEXT } from './server/referenceText.js';
|
|
14
15
|
import { registerSceneTools } from './server/sceneTools.js';
|
|
15
|
-
import { createStateContext, getSharedState } from './server/stateContext.js';
|
|
16
|
-
export { getSharedState };
|
|
16
|
+
import { createStateContext, getSharedState, getSharedStateJSON, getSceneElementsJSON, getTimelineJSON } from './server/stateContext.js';
|
|
17
|
+
export { getSharedState, getSharedStateJSON, getSceneElementsJSON, getTimelineJSON };
|
|
17
18
|
export function createServer(store, onStateChange) {
|
|
18
19
|
const server = new McpServer({ name: 'excalimate', version: PKG_VERSION });
|
|
19
20
|
const ctx = createStateContext(nanoid(8), server, onStateChange);
|
|
@@ -21,6 +22,7 @@ export function createServer(store, onStateChange) {
|
|
|
21
22
|
server.tool('get_examples', 'Returns few-shot examples showing how to create elements and animate them. Call this to learn common patterns.', {}, async () => ({ content: [{ type: 'text', text: EXAMPLES_TEXT }] }));
|
|
22
23
|
registerSceneTools(server, ctx, normalizeElements);
|
|
23
24
|
registerAnimationTools(server, ctx, getElementBounds);
|
|
25
|
+
registerCompositeTools(server, ctx, normalizeElements, getElementBounds);
|
|
24
26
|
registerQueryTools(server, ctx, geometry);
|
|
25
27
|
registerCheckpointTools(server, ctx, store);
|
|
26
28
|
registerShareTools(server, ctx);
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAGzI,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,eAAe,EAAE,CAAC;AAGrF,MAAM,UAAU,YAAY,CAC1B,KAAsB,EACtB,aAAmC;IAEnC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;IAC3E,MAAM,GAAG,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;IAEjE,MAAM,CAAC,IAAI,CACT,SAAS,EACT,mKAAmK,EACnK,EAAE,EACF,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,EAAE,CAAC,CACpE,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,cAAc,EACd,gHAAgH,EAChH,EAAE,EACF,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,EAAE,CAAC,CAC5E,CAAC;IAEF,kBAAkB,CAAC,MAAM,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAC;IACnD,sBAAsB,CAAC,MAAM,EAAE,GAAG,EAAE,gBAAgB,CAAC,CAAC;IACtD,sBAAsB,CAAC,MAAM,EAAE,GAAG,EAAE,iBAAiB,EAAE,gBAAgB,CAAC,CAAC;IACzE,kBAAkB,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC1C,uBAAuB,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IAC5C,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEhC,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/state.d.ts
CHANGED
|
@@ -12,4 +12,18 @@ export declare function ensureTrack(state: ServerState, targetId: string, proper
|
|
|
12
12
|
track: AnimationTrack;
|
|
13
13
|
};
|
|
14
14
|
export declare function addKeyframeToState(state: ServerState, targetId: string, property: AnimatableProperty, time: number, value: number, easing?: EasingType): ServerState;
|
|
15
|
+
/**
|
|
16
|
+
* Batch-add many keyframes in a single pass, avoiding per-keyframe state cloning.
|
|
17
|
+
*
|
|
18
|
+
* Groups keyframes by (targetId, property), creates/finds tracks once per group,
|
|
19
|
+
* appends all keyframes at once, sorts each track once at the end.
|
|
20
|
+
* Returns the final state in one shot.
|
|
21
|
+
*/
|
|
22
|
+
export declare function addKeyframesBatchToState(state: ServerState, keyframes: {
|
|
23
|
+
targetId: string;
|
|
24
|
+
property: AnimatableProperty;
|
|
25
|
+
time: number;
|
|
26
|
+
value: number;
|
|
27
|
+
easing?: EasingType;
|
|
28
|
+
}[]): ServerState;
|
|
15
29
|
//# sourceMappingURL=state.d.ts.map
|
package/dist/state.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,QAAQ,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExG,wBAAgB,kBAAkB,IAAI,WAAW,CAchD;AAID,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,SAAS,GAAG,OAAO,EAC/B,QAAQ,EAAE,kBAAkB,GAC3B,cAAc,CAShB;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,UAAqB,GAAG,QAAQ,CAEnG;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,QAAQ,GAAG,cAAc,CAGtF;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,CAEjG;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,kBAAkB,GAC3B;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,CAiB/C;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,kBAAkB,EAC5B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,MAAM,GAAE,UAAqB,GAC5B,WAAW,CAWb"}
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,QAAQ,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExG,wBAAgB,kBAAkB,IAAI,WAAW,CAchD;AAID,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,SAAS,GAAG,OAAO,EAC/B,QAAQ,EAAE,kBAAkB,GAC3B,cAAc,CAShB;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,UAAqB,GAAG,QAAQ,CAEnG;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,QAAQ,GAAG,cAAc,CAGtF;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,CAEjG;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,kBAAkB,GAC3B;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,CAiB/C;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,kBAAkB,EAC5B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,MAAM,GAAE,UAAqB,GAC5B,WAAW,CAWb;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,kBAAkB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,EAAE,GAChH,WAAW,CAwDb"}
|
package/dist/state.js
CHANGED
|
@@ -66,4 +66,61 @@ export function addKeyframeToState(state, targetId, property, time, value, easin
|
|
|
66
66
|
},
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Batch-add many keyframes in a single pass, avoiding per-keyframe state cloning.
|
|
71
|
+
*
|
|
72
|
+
* Groups keyframes by (targetId, property), creates/finds tracks once per group,
|
|
73
|
+
* appends all keyframes at once, sorts each track once at the end.
|
|
74
|
+
* Returns the final state in one shot.
|
|
75
|
+
*/
|
|
76
|
+
export function addKeyframesBatchToState(state, keyframes) {
|
|
77
|
+
if (keyframes.length === 0)
|
|
78
|
+
return state;
|
|
79
|
+
// Build a mutable copy of tracks array (shallow — track objects reused until modified)
|
|
80
|
+
const tracks = [...state.timeline.tracks];
|
|
81
|
+
// Index for O(1) track lookup: "targetId|property" → index in tracks[]
|
|
82
|
+
const trackIndex = new Map();
|
|
83
|
+
for (let i = 0; i < tracks.length; i++) {
|
|
84
|
+
trackIndex.set(`${tracks[i].targetId}|${tracks[i].property}`, i);
|
|
85
|
+
}
|
|
86
|
+
// Determine target type once per targetId
|
|
87
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
88
|
+
const elementIdSet = new Set(state.scene.elements.map((e) => e.id));
|
|
89
|
+
const targetTypeCache = new Map();
|
|
90
|
+
// Track which indices were cloned and need a final sort
|
|
91
|
+
const modifiedIndices = new Set();
|
|
92
|
+
for (const kf of keyframes) {
|
|
93
|
+
const key = `${kf.targetId}|${kf.property}`;
|
|
94
|
+
let idx = trackIndex.get(key);
|
|
95
|
+
if (idx === undefined) {
|
|
96
|
+
let targetType = targetTypeCache.get(kf.targetId);
|
|
97
|
+
if (targetType === undefined) {
|
|
98
|
+
targetType = elementIdSet.has(kf.targetId) ? 'element' : 'group';
|
|
99
|
+
targetTypeCache.set(kf.targetId, targetType);
|
|
100
|
+
}
|
|
101
|
+
const newTrack = createTrack(kf.targetId, targetType, kf.property);
|
|
102
|
+
idx = tracks.length;
|
|
103
|
+
tracks.push(newTrack);
|
|
104
|
+
trackIndex.set(key, idx);
|
|
105
|
+
}
|
|
106
|
+
// Clone track on first modification (copy-on-write)
|
|
107
|
+
if (!modifiedIndices.has(idx)) {
|
|
108
|
+
tracks[idx] = { ...tracks[idx], keyframes: [...tracks[idx].keyframes] };
|
|
109
|
+
modifiedIndices.add(idx);
|
|
110
|
+
}
|
|
111
|
+
// Append keyframe (defer sorting until the end)
|
|
112
|
+
tracks[idx].keyframes.push(createKeyframe(kf.time, kf.value, kf.easing ?? 'linear'));
|
|
113
|
+
}
|
|
114
|
+
// Sort keyframes once per modified track
|
|
115
|
+
for (const idx of modifiedIndices) {
|
|
116
|
+
tracks[idx].keyframes.sort((a, b) => a.time - b.time);
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
...state,
|
|
120
|
+
timeline: {
|
|
121
|
+
...state.timeline,
|
|
122
|
+
tracks,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
69
126
|
//# sourceMappingURL=state.js.map
|
package/dist/state.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@excalimate/mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Excalimate MCP server for creating Excalidraw designs and animating them with keyframes",
|
|
6
6
|
"keywords": [
|
|
@@ -30,7 +30,9 @@
|
|
|
30
30
|
"build": "tsc",
|
|
31
31
|
"start": "node dist/index.js",
|
|
32
32
|
"dev": "tsx watch src/index.ts",
|
|
33
|
-
"prepublishOnly": "npm run build"
|
|
33
|
+
"prepublishOnly": "npm run build",
|
|
34
|
+
"bench": "tsx bench/run.ts",
|
|
35
|
+
"bench:json": "tsx bench/run.ts --json"
|
|
34
36
|
},
|
|
35
37
|
"publishConfig": {
|
|
36
38
|
"access": "public",
|