@efectoapp/mcp-server 0.1.4 → 0.1.6
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/cli.d.ts +10 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +236 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +11 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -2
- package/dist/index.js.map +1 -1
- package/dist/tools/discovery.d.ts.map +1 -1
- package/dist/tools/discovery.js +118 -80
- package/dist/tools/discovery.js.map +1 -1
- package/dist/tools/state.d.ts +2 -3
- package/dist/tools/state.d.ts.map +1 -1
- package/dist/tools/state.js +210 -77
- package/dist/tools/state.js.map +1 -1
- package/package.json +1 -1
package/dist/tools/state.d.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
15
15
|
type AspectRatio = '16:9' | '9:16' | '1:1' | '4:3' | 'full';
|
|
16
16
|
type EffectId = 'none' | 'ascii-standard' | 'ascii-blocks' | 'ascii-braille' | 'ascii-hatching' | 'ascii-matrix' | 'ascii-technical' | 'ascii-dense' | 'ascii-minimal' | 'dither-floyd-steinberg' | 'dither-atkinson' | 'dither-jarvis-judice-ninke' | 'dither-stucki' | 'dither-burkes' | 'dither-sierra' | 'dither-two-row-sierra' | 'dither-sierra-lite' | 'color-separation' | 'halftone-mono' | 'halftone-cmyk' | 'glitch-chromatic' | 'glitch-digital' | 'glitch-vhs' | 'glitch-weird' | 'art-kuwahara' | 'art-crosshatch' | 'art-lineart' | 'art-engraving' | 'art-stipple' | 'special-warp';
|
|
17
|
-
type PostProcessType = 'scanlines' | 'vignette' | 'chromatic-aberration' | 'curvature' | 'grain' | 'noise' | 'pixelate' | 'wave' | 'rgb-glitch' | 'brightness-contrast' | 'color-tint' | 'palette' | 'jitter' | 'bloom' | 'dot-screen' | 'sepia' | 'grid' | 'light-beams' | '
|
|
17
|
+
type PostProcessType = 'scanlines' | 'vignette' | 'chromatic-aberration' | 'curvature' | 'grain' | 'noise' | 'pixelate' | 'wave' | 'rgb-glitch' | 'brightness-contrast' | 'color-tint' | 'palette' | 'jitter' | 'bloom' | 'dot-screen' | 'sepia' | 'grid' | 'light-beams' | 'motion-blur';
|
|
18
18
|
interface LayerTransform {
|
|
19
19
|
x: number;
|
|
20
20
|
y: number;
|
|
@@ -31,13 +31,12 @@ interface BaseLayer {
|
|
|
31
31
|
locked: boolean;
|
|
32
32
|
transform: LayerTransform;
|
|
33
33
|
}
|
|
34
|
-
type FontWeight = 'normal' | 'medium' | 'semibold' | 'bold';
|
|
35
34
|
interface TextLayer extends BaseLayer {
|
|
36
35
|
type: 'text';
|
|
37
36
|
content: string;
|
|
38
37
|
fontFamily: string;
|
|
39
38
|
fontSize: number;
|
|
40
|
-
fontWeight:
|
|
39
|
+
fontWeight: string;
|
|
41
40
|
color: string;
|
|
42
41
|
textAlign: 'left' | 'center' | 'right';
|
|
43
42
|
letterSpacing: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/tools/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAA;AAG9D,KAAK,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,CAAA;AAG3D,KAAK,QAAQ,GACT,MAAM,GAEN,gBAAgB,GAAG,cAAc,GAAG,eAAe,GAAG,gBAAgB,GACtE,cAAc,GAAG,iBAAiB,GAAG,aAAa,GAAG,eAAe,GAEpE,wBAAwB,GAAG,iBAAiB,GAAG,4BAA4B,GAC3E,eAAe,GAAG,eAAe,GAAG,eAAe,GAAG,uBAAuB,GAC7E,oBAAoB,GAAG,kBAAkB,GAEzC,eAAe,GAAG,eAAe,GAEjC,kBAAkB,GAAG,gBAAgB,GAAG,YAAY,GAAG,cAAc,GAErE,cAAc,GAAG,gBAAgB,GAAG,aAAa,GAAG,eAAe,GAAG,aAAa,GAEnF,cAAc,CAAA;AAGlB,KAAK,eAAe,GAChB,WAAW,GAAG,UAAU,GAAG,sBAAsB,GAAG,WAAW,GAC/D,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,YAAY,GAAG,qBAAqB,GAC9E,YAAY,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,YAAY,GAAG,OAAO,GACtE,MAAM,GAAG,aAAa,GAAG,
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/tools/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAA;AAG9D,KAAK,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,CAAA;AAG3D,KAAK,QAAQ,GACT,MAAM,GAEN,gBAAgB,GAAG,cAAc,GAAG,eAAe,GAAG,gBAAgB,GACtE,cAAc,GAAG,iBAAiB,GAAG,aAAa,GAAG,eAAe,GAEpE,wBAAwB,GAAG,iBAAiB,GAAG,4BAA4B,GAC3E,eAAe,GAAG,eAAe,GAAG,eAAe,GAAG,uBAAuB,GAC7E,oBAAoB,GAAG,kBAAkB,GAEzC,eAAe,GAAG,eAAe,GAEjC,kBAAkB,GAAG,gBAAgB,GAAG,YAAY,GAAG,cAAc,GAErE,cAAc,GAAG,gBAAgB,GAAG,aAAa,GAAG,eAAe,GAAG,aAAa,GAEnF,cAAc,CAAA;AAGlB,KAAK,eAAe,GAChB,WAAW,GAAG,UAAU,GAAG,sBAAsB,GAAG,WAAW,GAC/D,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,YAAY,GAAG,qBAAqB,GAC9E,YAAY,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,YAAY,GAAG,OAAO,GACtE,MAAM,GAAG,aAAa,GAAG,aAAa,CAAA;AAU1C,UAAU,cAAc;IACtB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;CAChB;AAGD,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,OAAO,CAAA;IACf,SAAS,EAAE,cAAc,CAAA;CAC1B;AAGD,UAAU,SAAU,SAAQ,SAAS;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;IACtC,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;CACnB;AAGD,UAAU,UAAW,SAAQ,SAAS;IACpC,IAAI,EAAE,OAAO,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,OAAO,GAAG,SAAS,CAAA;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;CACnB;AAGD,UAAU,UAAW,SAAQ,SAAS;IACpC,IAAI,EAAE,OAAO,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,OAAO,GAAG,SAAS,CAAA;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,OAAO,CAAA;IACb,aAAa,EAAE,MAAM,CAAA;CACtB;AAGD,KAAK,qBAAqB,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,IAAI,GAAG,QAAQ,CAAA;AAG1E,UAAU,eAAgB,SAAQ,SAAS;IACzC,IAAI,EAAE,YAAY,CAAA;IAClB,WAAW,EAAE,qBAAqB,CAAA;IAClC,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE;QACX,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,EAAE,OAAO,GAAG,OAAO,CAAA;QAC5B,UAAU,EAAE,MAAM,CAAA;QAClB,QAAQ,EAAE,MAAM,CAAA;QAChB,UAAU,EAAE,MAAM,CAAA;QAClB,SAAS,EAAE,OAAO,GAAG,SAAS,CAAA;KAC/B,CAAA;CACF;AAGD,KAAK,KAAK,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,eAAe,GAAG,SAAS,CAAA;AAG9E,UAAU,mBAAmB;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,eAAe,CAAA;IACrB,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC;AAGD,UAAU,WAAW;IACnB,MAAM,EAAE;QACN,WAAW,EAAE,WAAW,CAAA;QACxB,eAAe,EAAE,MAAM,CAAA;KACxB,CAAA;IACD,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,MAAM,CAAC,EAAE;QACP,QAAQ,EAAE,QAAQ,CAAA;QAClB,OAAO,EAAE,OAAO,CAAA;QAEhB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAChC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAClC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACtC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACtC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACnC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAChC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAClC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACpC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACjC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACnC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACjC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KACnC,CAAA;IACD,aAAa,EAAE,mBAAmB,EAAE,CAAA;CACrC;AAMD,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAGD,wBAAgB,eAAe,IAAI,WAAW,GAAG,IAAI,CAEpD;AAgFD,eAAO,MAAM,UAAU,EAAE,IAAI,EAwR5B,CAAA;AAsBD;;GAEG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GACxC,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAiuB7D"}
|
package/dist/tools/state.js
CHANGED
|
@@ -17,27 +17,12 @@ exports.stateTools = void 0;
|
|
|
17
17
|
exports.resetState = resetState;
|
|
18
18
|
exports.getCurrentState = getCurrentState;
|
|
19
19
|
exports.handleStateTool = handleStateTool;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (
|
|
24
|
-
return
|
|
25
|
-
|
|
26
|
-
if (VALID_FONT_WEIGHTS.includes(normalized)) {
|
|
27
|
-
return normalized;
|
|
28
|
-
}
|
|
29
|
-
// Map numeric weights to closest valid weight
|
|
30
|
-
const numWeight = parseInt(normalized);
|
|
31
|
-
if (!isNaN(numWeight)) {
|
|
32
|
-
if (numWeight <= 400)
|
|
33
|
-
return 'normal';
|
|
34
|
-
if (numWeight <= 500)
|
|
35
|
-
return 'medium';
|
|
36
|
-
if (numWeight <= 600)
|
|
37
|
-
return 'semibold';
|
|
38
|
-
return 'bold';
|
|
39
|
-
}
|
|
40
|
-
return 'bold'; // fallback
|
|
20
|
+
// Helper to clamp values to valid ranges
|
|
21
|
+
function clamp(value, min, max, fallback) {
|
|
22
|
+
const v = value ?? fallback;
|
|
23
|
+
if (isNaN(v))
|
|
24
|
+
return fallback;
|
|
25
|
+
return Math.min(max, Math.max(min, v));
|
|
41
26
|
}
|
|
42
27
|
// Current poster state (single poster for now)
|
|
43
28
|
let currentPoster = null;
|
|
@@ -53,6 +38,51 @@ function getCurrentState() {
|
|
|
53
38
|
function generateId() {
|
|
54
39
|
return `layer_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
|
55
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Normalize font weight from various formats to our supported weights.
|
|
43
|
+
* Handles numeric weights (100-900) and common name variations.
|
|
44
|
+
* Our supported weights: normal (400), medium (500), semibold (600), bold (700)
|
|
45
|
+
*/
|
|
46
|
+
function normalizeFontWeight(input) {
|
|
47
|
+
if (input === undefined || input === null || input === '') {
|
|
48
|
+
return 'bold'; // default for new text layers
|
|
49
|
+
}
|
|
50
|
+
const str = String(input).toLowerCase().trim();
|
|
51
|
+
// Check if it's already a valid weight name
|
|
52
|
+
const validWeights = ['normal', 'medium', 'semibold', 'bold'];
|
|
53
|
+
if (validWeights.includes(str)) {
|
|
54
|
+
return str;
|
|
55
|
+
}
|
|
56
|
+
// Map numeric weights to our supported weights
|
|
57
|
+
const numericWeight = parseInt(str, 10);
|
|
58
|
+
if (!isNaN(numericWeight)) {
|
|
59
|
+
if (numericWeight <= 450)
|
|
60
|
+
return 'normal'; // 100-450 → normal (400)
|
|
61
|
+
if (numericWeight <= 550)
|
|
62
|
+
return 'medium'; // 451-550 → medium (500)
|
|
63
|
+
if (numericWeight <= 650)
|
|
64
|
+
return 'semibold'; // 551-650 → semibold (600)
|
|
65
|
+
return 'bold'; // 651+ → bold (700)
|
|
66
|
+
}
|
|
67
|
+
// Map common font weight name variations
|
|
68
|
+
const weightNameMap = {
|
|
69
|
+
// Thin/Light → normal
|
|
70
|
+
'thin': 'normal', 'hairline': 'normal', 'ultrathin': 'normal',
|
|
71
|
+
'extralight': 'normal', 'ultralight': 'normal', 'light': 'normal',
|
|
72
|
+
'regular': 'normal', 'book': 'normal', 'roman': 'normal',
|
|
73
|
+
// Medium
|
|
74
|
+
'med': 'medium',
|
|
75
|
+
// Semibold variations
|
|
76
|
+
'semibold': 'semibold', 'semi-bold': 'semibold', 'demibold': 'semibold',
|
|
77
|
+
'demi-bold': 'semibold', 'demi': 'semibold',
|
|
78
|
+
// Bold and heavier → bold
|
|
79
|
+
'extrabold': 'bold', 'ultrabold': 'bold', 'black': 'bold',
|
|
80
|
+
'heavy': 'bold', 'extrablack': 'bold', 'fat': 'bold',
|
|
81
|
+
};
|
|
82
|
+
// Try lookup with normalized string (remove spaces/hyphens)
|
|
83
|
+
const normalized = str.replace(/[\s-]/g, '');
|
|
84
|
+
return weightNameMap[normalized] || weightNameMap[str] || 'bold';
|
|
85
|
+
}
|
|
56
86
|
// Create default background layer
|
|
57
87
|
function createDefaultBackgroundLayer(backgroundColor) {
|
|
58
88
|
return {
|
|
@@ -143,9 +173,8 @@ exports.stateTools = [
|
|
|
143
173
|
},
|
|
144
174
|
name: { type: 'string', description: 'Layer name' },
|
|
145
175
|
// Transform properties (normalized coordinates relative to canvas)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
y: { type: 'number', description: 'Y position (-1 to 1, 0 is center). IMPORTANT: +1 = TOP, -1 = BOTTOM (opposite of screen coords!)', default: 0 },
|
|
176
|
+
x: { type: 'number', description: 'X position (-1 to 1, 0 is center, positive is right)', default: 0 },
|
|
177
|
+
y: { type: 'number', description: 'Y position (-1 to 1, 0 is center, POSITIVE is UP/TOP, negative is down/bottom)', default: 0 },
|
|
149
178
|
width: { type: 'number', description: 'Width (0-1 relative to canvas)', default: 1 },
|
|
150
179
|
height: { type: 'number', description: 'Height (0-1 relative to canvas)', default: 1 },
|
|
151
180
|
rotation: { type: 'number', description: 'Rotation in degrees', default: 0 },
|
|
@@ -154,7 +183,7 @@ exports.stateTools = [
|
|
|
154
183
|
content: { type: 'string', description: 'Text content (required for text layers)' },
|
|
155
184
|
fontFamily: { type: 'string', description: 'Font family name', default: 'DM Sans' },
|
|
156
185
|
fontSize: { type: 'number', description: 'Font size in pixels', default: 48 },
|
|
157
|
-
fontWeight: { type: 'string', enum: ['normal', '
|
|
186
|
+
fontWeight: { type: 'string', enum: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'], description: 'Font weight', default: 'bold' },
|
|
158
187
|
color: { type: 'string', description: 'Text color in hex', default: '#ffffff' },
|
|
159
188
|
textAlign: { type: 'string', enum: ['left', 'center', 'right'], description: 'Text alignment', default: 'center' },
|
|
160
189
|
letterSpacing: { type: 'number', description: 'Letter spacing in pixels', default: 0 },
|
|
@@ -173,9 +202,9 @@ exports.stateTools = [
|
|
|
173
202
|
type: 'object',
|
|
174
203
|
properties: {
|
|
175
204
|
layerId: { type: 'string', description: 'ID of the layer to modify' },
|
|
176
|
-
// Transform properties
|
|
177
|
-
x: { type: 'number', description: 'X position (-1 to 1
|
|
178
|
-
y: { type: 'number', description: 'Y position (-1 to 1
|
|
205
|
+
// Transform properties (positive Y is UP/TOP, negative Y is down/bottom)
|
|
206
|
+
x: { type: 'number', description: 'X position (-1 to 1, 0 is center)' },
|
|
207
|
+
y: { type: 'number', description: 'Y position (-1 to 1, POSITIVE is UP/TOP, negative is down/bottom)' },
|
|
179
208
|
width: { type: 'number', description: 'Width' },
|
|
180
209
|
height: { type: 'number', description: 'Height' },
|
|
181
210
|
rotation: { type: 'number', description: 'Rotation in degrees' },
|
|
@@ -201,7 +230,11 @@ exports.stateTools = [
|
|
|
201
230
|
},
|
|
202
231
|
{
|
|
203
232
|
name: 'apply_effect',
|
|
204
|
-
description:
|
|
233
|
+
description: `Apply or update the main effect. Only one effect can be active at a time.
|
|
234
|
+
|
|
235
|
+
IMPORTANT - Two effect pipelines:
|
|
236
|
+
1. DITHER effects (WebGL): Have BUILT-IN palette and bloom. Use paletteId/colors/bloomEnabled params here. Post-processes do NOT work with dither.
|
|
237
|
+
2. OTHER effects (WebGPU - ASCII, Glitch, Halftone, Art): Support stackable post-processes. Use add_postprocess for palette/bloom.`,
|
|
205
238
|
inputSchema: {
|
|
206
239
|
type: 'object',
|
|
207
240
|
properties: {
|
|
@@ -209,18 +242,18 @@ exports.stateTools = [
|
|
|
209
242
|
type: 'string',
|
|
210
243
|
enum: [
|
|
211
244
|
'none',
|
|
212
|
-
// ASCII
|
|
245
|
+
// ASCII (WebGPU - supports post-processes)
|
|
213
246
|
'ascii-standard', 'ascii-blocks', 'ascii-braille', 'ascii-hatching',
|
|
214
247
|
'ascii-matrix', 'ascii-technical', 'ascii-dense', 'ascii-minimal',
|
|
215
|
-
// Dither
|
|
248
|
+
// Dither (WebGL - has built-in palette/bloom, NO post-process support)
|
|
216
249
|
'dither-floyd-steinberg', 'dither-atkinson', 'dither-jarvis-judice-ninke',
|
|
217
250
|
'dither-stucki', 'dither-burkes', 'dither-sierra', 'dither-two-row-sierra',
|
|
218
251
|
'dither-sierra-lite', 'color-separation',
|
|
219
|
-
// Halftone
|
|
252
|
+
// Halftone (WebGPU - supports post-processes)
|
|
220
253
|
'halftone-mono', 'halftone-cmyk',
|
|
221
|
-
// Glitch
|
|
254
|
+
// Glitch (WebGPU - supports post-processes)
|
|
222
255
|
'glitch-chromatic', 'glitch-digital', 'glitch-vhs', 'glitch-weird',
|
|
223
|
-
// Art
|
|
256
|
+
// Art (WebGPU - supports post-processes)
|
|
224
257
|
'art-kuwahara', 'art-crosshatch', 'art-lineart', 'art-engraving', 'art-stipple',
|
|
225
258
|
// Special
|
|
226
259
|
'special-warp',
|
|
@@ -232,21 +265,34 @@ exports.stateTools = [
|
|
|
232
265
|
cellSize: { type: 'number', description: 'Cell size for ASCII effects (4-32)', default: 8 },
|
|
233
266
|
color: { type: 'boolean', description: 'Enable color mode for ASCII', default: true },
|
|
234
267
|
invert: { type: 'boolean', description: 'Invert ASCII effect', default: false },
|
|
235
|
-
// Dither effect settings
|
|
236
|
-
pixelation: { type: 'number', description: 'Pixelation level for dither (1-
|
|
237
|
-
|
|
268
|
+
// Dither effect settings (WebGL - has built-in palette/bloom)
|
|
269
|
+
pixelation: { type: 'number', description: 'Pixelation level for dither (1-20)', default: 3 },
|
|
270
|
+
paletteId: { type: 'string', description: 'DITHER ONLY: Palette ID (e.g., "gameboy", "synthwave", "cyberpunk", "noir"). Use list_palettes to see all 37 options.' },
|
|
271
|
+
colors: { type: 'array', items: { type: 'string' }, description: 'DITHER ONLY: Custom color palette as hex array (used when paletteId is null)' },
|
|
272
|
+
bloomEnabled: { type: 'boolean', description: 'DITHER ONLY: Enable built-in bloom glow effect', default: false },
|
|
273
|
+
bloomIntensity: { type: 'number', description: 'DITHER ONLY: Bloom intensity (0-3)', default: 0.5 },
|
|
274
|
+
bloomRadius: { type: 'number', description: 'DITHER ONLY: Bloom blur radius (1-100)', default: 20 },
|
|
238
275
|
// Halftone effect settings
|
|
239
|
-
dotSize: { type: 'number', description: 'Dot size for halftone effects' },
|
|
276
|
+
dotSize: { type: 'number', description: 'Dot size for halftone effects (0-1, default 0.3)', default: 0.3 },
|
|
240
277
|
// Glitch effect settings
|
|
241
|
-
intensity: { type: 'number', description: 'Glitch intensity (0-1)' },
|
|
242
|
-
speed: { type: 'number', description: 'Glitch animation speed' },
|
|
278
|
+
intensity: { type: 'number', description: 'Glitch intensity (0-1)', default: 0.5 },
|
|
279
|
+
speed: { type: 'number', description: 'Glitch animation speed (0-2)', default: 1 },
|
|
243
280
|
},
|
|
244
281
|
required: ['effectId'],
|
|
245
282
|
},
|
|
246
283
|
},
|
|
247
284
|
{
|
|
248
285
|
name: 'add_postprocess',
|
|
249
|
-
description:
|
|
286
|
+
description: `Add a stackable post-processing effect. Can add multiple post-processes that apply in order.
|
|
287
|
+
|
|
288
|
+
IMPORTANT: Post-processes only work with WebGPU effects (ASCII, Glitch, Halftone, Art).
|
|
289
|
+
They do NOT work with Dither effects (WebGL) - use apply_effect params for dither palette/bloom instead.
|
|
290
|
+
|
|
291
|
+
Common combinations:
|
|
292
|
+
- CRT look: scanlines + curvature + vignette + chromatic-aberration
|
|
293
|
+
- Film look: grain + vignette + brightness-contrast
|
|
294
|
+
- Cyberpunk: bloom + chromatic-aberration + scanlines
|
|
295
|
+
- Vaporwave: palette + bloom + chromatic-aberration`,
|
|
250
296
|
inputSchema: {
|
|
251
297
|
type: 'object',
|
|
252
298
|
properties: {
|
|
@@ -256,28 +302,64 @@ exports.stateTools = [
|
|
|
256
302
|
'scanlines', 'vignette', 'chromatic-aberration', 'curvature',
|
|
257
303
|
'grain', 'noise', 'pixelate', 'wave', 'rgb-glitch', 'brightness-contrast',
|
|
258
304
|
'color-tint', 'palette', 'jitter', 'bloom', 'dot-screen', 'sepia',
|
|
259
|
-
'grid', 'light-beams', '
|
|
305
|
+
'grid', 'light-beams', 'motion-blur',
|
|
260
306
|
],
|
|
261
307
|
description: 'Post-process type',
|
|
262
308
|
},
|
|
263
309
|
enabled: { type: 'boolean', description: 'Whether effect is enabled', default: true },
|
|
264
|
-
//
|
|
265
|
-
intensity: { type: 'number', description: 'Effect intensity' },
|
|
310
|
+
// Shared parameters (used by multiple post-processes)
|
|
311
|
+
intensity: { type: 'number', description: 'Effect intensity - Scanlines: 0-1; Bloom: 0-3 (glow strength); Sepia: 0-1', default: 0.5 },
|
|
312
|
+
radius: { type: 'number', description: 'Effect radius - Vignette: 0.5-1.5; Bloom: 0-1 (blur radius)', default: 0.4 },
|
|
266
313
|
// Scanlines
|
|
267
|
-
count: { type: 'number', description: '
|
|
268
|
-
// Vignette
|
|
269
|
-
radius: { type: 'number', description: 'Vignette radius' },
|
|
314
|
+
count: { type: 'number', description: 'Scanlines: number of lines (100-1000)', default: 400 },
|
|
270
315
|
// Chromatic aberration
|
|
271
|
-
strength: { type: 'number', description: '
|
|
272
|
-
angle: { type: 'number', description: '
|
|
316
|
+
strength: { type: 'number', description: 'Chromatic aberration: separation strength (0-0.1)', default: 0.01 },
|
|
317
|
+
angle: { type: 'number', description: 'Chromatic aberration: separation direction (0-360)', default: 0 },
|
|
273
318
|
// Grain
|
|
274
|
-
size: { type: 'number', description: 'Grain size' },
|
|
275
|
-
speed: { type: 'number', description: 'Animation speed' },
|
|
319
|
+
size: { type: 'number', description: 'Grain: particle size (1-3)', default: 1.5 },
|
|
320
|
+
speed: { type: 'number', description: 'Animation speed for grain/noise/wave/jitter', default: 1 },
|
|
321
|
+
colorAmount: { type: 'number', description: 'Grain: color vs monochrome (0-1)', default: 0 },
|
|
276
322
|
// Brightness/Contrast
|
|
277
|
-
brightness: { type: 'number', description: 'Brightness adjustment' },
|
|
278
|
-
contrast: { type: 'number', description: 'Contrast adjustment' },
|
|
279
|
-
saturation: { type: 'number', description: 'Saturation adjustment' },
|
|
280
|
-
hue: { type: 'number', description: 'Hue rotation' },
|
|
323
|
+
brightness: { type: 'number', description: 'Brightness: adjustment (-1 to 1)', default: 0 },
|
|
324
|
+
contrast: { type: 'number', description: 'Contrast: adjustment (0-2, 1=normal)', default: 1 },
|
|
325
|
+
saturation: { type: 'number', description: 'Saturation: adjustment (0-2, 1=normal)', default: 1 },
|
|
326
|
+
hue: { type: 'number', description: 'Hue: rotation (-0.5 to 0.5)', default: 0 },
|
|
327
|
+
// Bloom (WebGPU post-process version)
|
|
328
|
+
threshold: { type: 'number', description: 'Bloom: luminance threshold (0-1)', default: 0.2 },
|
|
329
|
+
// Palette (WebGPU post-process version)
|
|
330
|
+
paletteId: { type: 'string', description: 'Palette: built-in palette ID (use list_palettes)' },
|
|
331
|
+
colors: { type: 'array', items: { type: 'string' }, description: 'Palette: custom gradient colors as hex array' },
|
|
332
|
+
// Curvature
|
|
333
|
+
curvature: { type: 'number', description: 'Curvature: CRT curve intensity (0-1)', default: 0.3 },
|
|
334
|
+
// Pixelate
|
|
335
|
+
pixelSize: { type: 'number', description: 'Pixelate: block size (1-50)', default: 4 },
|
|
336
|
+
// Wave
|
|
337
|
+
amplitude: { type: 'number', description: 'Wave: height (0-1)', default: 0.1 },
|
|
338
|
+
frequency: { type: 'number', description: 'Wave: frequency (1-20)', default: 5 },
|
|
339
|
+
// Sepia
|
|
340
|
+
// intensity already defined above
|
|
341
|
+
// Grid
|
|
342
|
+
scale: { type: 'number', description: 'Grid: cell size (1-50)', default: 20 },
|
|
343
|
+
lineWidth: { type: 'number', description: 'Grid: line thickness (1-10)', default: 1 },
|
|
344
|
+
color: { type: 'string', description: 'Grid: line color (hex)', default: '#ffffff' },
|
|
345
|
+
rotation: { type: 'number', description: 'Grid: rotation in degrees (0-360)', default: 0 },
|
|
346
|
+
// Noise
|
|
347
|
+
colored: { type: 'boolean', description: 'Noise: color vs monochrome', default: false },
|
|
348
|
+
// Color Tint
|
|
349
|
+
palette: { type: 'string', enum: ['original', 'green', 'amber', 'cyan', 'blue'], description: 'Color-tint: terminal color preset', default: 'green' },
|
|
350
|
+
// Motion Blur
|
|
351
|
+
blurType: { type: 'string', enum: ['linear', 'radial', 'rotational'], description: 'Motion-blur: blur type', default: 'linear' },
|
|
352
|
+
samples: { type: 'number', description: 'Motion-blur: quality (4-48)', default: 16 },
|
|
353
|
+
centerX: { type: 'number', description: 'Motion-blur: center X for radial/rotational (0-1)', default: 0.5 },
|
|
354
|
+
centerY: { type: 'number', description: 'Motion-blur: center Y for radial/rotational (0-1)', default: 0.5 },
|
|
355
|
+
// Light Beams
|
|
356
|
+
lightX: { type: 'number', description: 'Light-beams: source X position (0-1)', default: 0.5 },
|
|
357
|
+
lightY: { type: 'number', description: 'Light-beams: source Y position (0-1)', default: 0.3 },
|
|
358
|
+
exposure: { type: 'number', description: 'Light-beams: ray brightness (0-1)', default: 0.3 },
|
|
359
|
+
decay: { type: 'number', description: 'Light-beams: ray fade (0.9-1.0)', default: 0.96 },
|
|
360
|
+
density: { type: 'number', description: 'Light-beams: ray spread (0.5-2)', default: 1 },
|
|
361
|
+
animated: { type: 'boolean', description: 'Light-beams/Grid: enable animation', default: false },
|
|
362
|
+
particleAmount: { type: 'number', description: 'Light-beams: particle density (0-1)', default: 0.5 },
|
|
281
363
|
},
|
|
282
364
|
required: ['type'],
|
|
283
365
|
},
|
|
@@ -459,7 +541,7 @@ async function handleStateTool(name, args) {
|
|
|
459
541
|
content: params.content || 'Text',
|
|
460
542
|
fontFamily: params.fontFamily || 'DM Sans',
|
|
461
543
|
fontSize: params.fontSize || 48,
|
|
462
|
-
fontWeight:
|
|
544
|
+
fontWeight: normalizeFontWeight(params.fontWeight),
|
|
463
545
|
color: params.color || '#ffffff',
|
|
464
546
|
textAlign: params.textAlign || 'center',
|
|
465
547
|
letterSpacing: params.letterSpacing ?? 0,
|
|
@@ -561,7 +643,7 @@ async function handleStateTool(name, args) {
|
|
|
561
643
|
if (params.fontSize !== undefined)
|
|
562
644
|
textLayer.fontSize = params.fontSize;
|
|
563
645
|
if (params.fontWeight !== undefined)
|
|
564
|
-
textLayer.fontWeight =
|
|
646
|
+
textLayer.fontWeight = normalizeFontWeight(params.fontWeight);
|
|
565
647
|
if (params.color !== undefined)
|
|
566
648
|
textLayer.color = params.color;
|
|
567
649
|
if (params.textAlign !== undefined)
|
|
@@ -626,7 +708,7 @@ async function handleStateTool(name, args) {
|
|
|
626
708
|
const style = effectId.replace('ascii-', '');
|
|
627
709
|
effect.ascii = {
|
|
628
710
|
style,
|
|
629
|
-
cellSize: params.cellSize
|
|
711
|
+
cellSize: clamp(params.cellSize, 4, 32, 9),
|
|
630
712
|
invert: params.invert ?? false,
|
|
631
713
|
color: params.color ?? true,
|
|
632
714
|
charRotation: false,
|
|
@@ -671,17 +753,21 @@ async function handleStateTool(name, args) {
|
|
|
671
753
|
'dither-sierra-lite': 'sierraLite',
|
|
672
754
|
'color-separation': 'floydSteinberg',
|
|
673
755
|
};
|
|
756
|
+
// Dither has BUILT-IN palette and bloom (WebGL pipeline)
|
|
757
|
+
// These don't use post-processes - settings are on the effect itself
|
|
674
758
|
effect.dither = {
|
|
675
759
|
pattern: patternMap[effectId] || 'floydSteinberg',
|
|
676
|
-
pixelation: params.pixelation
|
|
677
|
-
|
|
760
|
+
pixelation: clamp(params.pixelation, 1, 20, 3),
|
|
761
|
+
// Palette: use paletteId for built-in palette, or custom colors array
|
|
762
|
+
paletteId: params.paletteId ?? null,
|
|
678
763
|
colors: params.colors ?? ['#000000', '#ffffff'],
|
|
679
|
-
brightness: params.brightness
|
|
680
|
-
contrast: params.contrast
|
|
764
|
+
brightness: clamp(params.brightness, 0, 2, 1),
|
|
765
|
+
contrast: clamp(params.contrast, 0.5, 2, 1.2),
|
|
681
766
|
threshold: 1.0,
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
767
|
+
// Built-in bloom for dither (not a post-process)
|
|
768
|
+
bloomEnabled: params.bloomEnabled ?? false,
|
|
769
|
+
bloomIntensity: clamp(params.bloomIntensity, 0, 3, 0.5),
|
|
770
|
+
bloomRadius: clamp(params.bloomRadius, 1, 100, 20),
|
|
685
771
|
};
|
|
686
772
|
}
|
|
687
773
|
else if (settingsKey === 'monoHalftone') {
|
|
@@ -692,7 +778,7 @@ async function handleStateTool(name, args) {
|
|
|
692
778
|
gridType: 'square',
|
|
693
779
|
dotType: 'circle',
|
|
694
780
|
inverted: false,
|
|
695
|
-
size: params.dotSize
|
|
781
|
+
size: clamp(params.dotSize, 0, 1, 0.3),
|
|
696
782
|
radius: 0.5,
|
|
697
783
|
contrast: 1.2,
|
|
698
784
|
spread: 0.3,
|
|
@@ -707,7 +793,7 @@ async function handleStateTool(name, args) {
|
|
|
707
793
|
colorM: '#ec008c',
|
|
708
794
|
colorY: '#fff200',
|
|
709
795
|
colorK: '#231f20',
|
|
710
|
-
size: params.dotSize
|
|
796
|
+
size: clamp(params.dotSize, 0, 1, 0.3),
|
|
711
797
|
gridNoise: 0.0,
|
|
712
798
|
type: 'ink',
|
|
713
799
|
softness: 0.0,
|
|
@@ -771,7 +857,7 @@ async function handleStateTool(name, args) {
|
|
|
771
857
|
localWarpStrength: 0.14,
|
|
772
858
|
flipChance: 0.15,
|
|
773
859
|
// Shared
|
|
774
|
-
speed: params.speed
|
|
860
|
+
speed: clamp(params.speed, 0, 2, 1),
|
|
775
861
|
animated: true,
|
|
776
862
|
};
|
|
777
863
|
}
|
|
@@ -872,18 +958,58 @@ async function handleStateTool(name, args) {
|
|
|
872
958
|
content: [{ type: 'text', text: 'Error: Post-process type is required' }],
|
|
873
959
|
};
|
|
874
960
|
}
|
|
961
|
+
// Check if dither effect is active - post-processes don't work with WebGL dither
|
|
962
|
+
const isDitherActive = currentPoster.effect?.effectId?.startsWith('dither-') ||
|
|
963
|
+
currentPoster.effect?.effectId === 'color-separation';
|
|
875
964
|
const ppId = `pp_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
|
|
876
965
|
const settings = {};
|
|
877
|
-
// Extract relevant settings based on type
|
|
878
|
-
|
|
966
|
+
// Extract ALL relevant settings based on type
|
|
967
|
+
// Common settings
|
|
968
|
+
const commonKeys = [
|
|
879
969
|
'intensity', 'count', 'radius', 'strength', 'angle', 'size', 'speed',
|
|
880
970
|
'brightness', 'contrast', 'saturation', 'hue',
|
|
881
971
|
];
|
|
882
|
-
|
|
972
|
+
// Additional settings for specific post-process types
|
|
973
|
+
const additionalKeys = [
|
|
974
|
+
'colorAmount', // grain
|
|
975
|
+
'colored', // noise
|
|
976
|
+
'threshold', // bloom
|
|
977
|
+
'paletteId', // palette
|
|
978
|
+
'colors', // palette
|
|
979
|
+
'palette', // color-tint
|
|
980
|
+
'curvature', // curvature
|
|
981
|
+
'pixelSize', // pixelate
|
|
982
|
+
'amplitude', // wave
|
|
983
|
+
'frequency', // wave, rgb-glitch
|
|
984
|
+
'scale', // grid
|
|
985
|
+
'lineWidth', // grid
|
|
986
|
+
'color', // grid
|
|
987
|
+
'rotation', // grid
|
|
988
|
+
'animated', // grid, light-beams
|
|
989
|
+
// Motion blur
|
|
990
|
+
'blurType', // motion-blur (maps to 'type')
|
|
991
|
+
'samples', // motion-blur
|
|
992
|
+
'centerX', // motion-blur
|
|
993
|
+
'centerY', // motion-blur
|
|
994
|
+
// Light beams
|
|
995
|
+
'lightX', // light-beams
|
|
996
|
+
'lightY', // light-beams
|
|
997
|
+
'exposure', // light-beams
|
|
998
|
+
'decay', // light-beams
|
|
999
|
+
'density', // light-beams
|
|
1000
|
+
'particleAmount', // light-beams
|
|
1001
|
+
];
|
|
1002
|
+
const allSettingKeys = [...commonKeys, ...additionalKeys];
|
|
1003
|
+
for (const key of allSettingKeys) {
|
|
883
1004
|
if (params[key] !== undefined) {
|
|
884
1005
|
settings[key] = params[key];
|
|
885
1006
|
}
|
|
886
1007
|
}
|
|
1008
|
+
// Special handling: motion-blur uses 'type' internally but we use 'blurType' to avoid schema conflict
|
|
1009
|
+
if (ppType === 'motion-blur' && settings.blurType) {
|
|
1010
|
+
settings.type = settings.blurType;
|
|
1011
|
+
delete settings.blurType;
|
|
1012
|
+
}
|
|
887
1013
|
const postProcess = {
|
|
888
1014
|
id: ppId,
|
|
889
1015
|
type: ppType,
|
|
@@ -891,16 +1017,23 @@ async function handleStateTool(name, args) {
|
|
|
891
1017
|
settings,
|
|
892
1018
|
};
|
|
893
1019
|
currentPoster.postProcesses.push(postProcess);
|
|
1020
|
+
// Build response with warning if dither is active
|
|
1021
|
+
const response = {
|
|
1022
|
+
success: true,
|
|
1023
|
+
message: 'Post-process added',
|
|
1024
|
+
postProcess,
|
|
1025
|
+
totalPostProcesses: currentPoster.postProcesses.length,
|
|
1026
|
+
};
|
|
1027
|
+
if (isDitherActive) {
|
|
1028
|
+
response.warning = 'WARNING: Dither effects use WebGL and do NOT support post-processes. ' +
|
|
1029
|
+
'This post-process will NOT be visible. For dither, use apply_effect params (paletteId, bloomEnabled) instead. ' +
|
|
1030
|
+
'Post-processes only work with WebGPU effects (ASCII, Glitch, Halftone, Art).';
|
|
1031
|
+
}
|
|
894
1032
|
return {
|
|
895
1033
|
content: [
|
|
896
1034
|
{
|
|
897
1035
|
type: 'text',
|
|
898
|
-
text: JSON.stringify(
|
|
899
|
-
success: true,
|
|
900
|
-
message: 'Post-process added',
|
|
901
|
-
postProcess,
|
|
902
|
-
totalPostProcesses: currentPoster.postProcesses.length,
|
|
903
|
-
}, null, 2),
|
|
1036
|
+
text: JSON.stringify(response, null, 2),
|
|
904
1037
|
},
|
|
905
1038
|
],
|
|
906
1039
|
};
|