@cyanheads/pixoo-mcp-server 1.2.1 → 1.2.2
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/AGENTS.md +5 -2
- package/CLAUDE.md +5 -2
- package/README.md +13 -9
- package/changelog/1.2.x/1.2.2.md +40 -0
- package/dist/mcp-server/resources/definitions/pixoo-design-guide.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/pixoo-design-guide.resource.js +4 -1
- package/dist/mcp-server/resources/definitions/pixoo-design-guide.resource.js.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-compose-scene.tool.d.ts +96 -2
- package/dist/mcp-server/tools/definitions/pixoo-compose-scene.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-compose-scene.tool.js +85 -10
- package/dist/mcp-server/tools/definitions/pixoo-compose-scene.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-design-brief.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-design-brief.tool.js +14 -6
- package/dist/mcp-server/tools/definitions/pixoo-design-brief.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-display-text.tool.d.ts +2 -0
- package/dist/mcp-server/tools/definitions/pixoo-display-text.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-display-text.tool.js +27 -12
- package/dist/mcp-server/tools/definitions/pixoo-display-text.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-push-image.tool.d.ts +30 -1
- package/dist/mcp-server/tools/definitions/pixoo-push-image.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-push-image.tool.js +105 -26
- package/dist/mcp-server/tools/definitions/pixoo-push-image.tool.js.map +1 -1
- package/dist/mcp-server/tools/finish-schema.d.ts +28 -0
- package/dist/mcp-server/tools/finish-schema.d.ts.map +1 -0
- package/dist/mcp-server/tools/finish-schema.js +42 -0
- package/dist/mcp-server/tools/finish-schema.js.map +1 -0
- package/dist/renderer/finish.d.ts +34 -0
- package/dist/renderer/finish.d.ts.map +1 -0
- package/dist/renderer/finish.js +62 -0
- package/dist/renderer/finish.js.map +1 -0
- package/dist/renderer/keyframes.d.ts +5 -1
- package/dist/renderer/keyframes.d.ts.map +1 -1
- package/dist/renderer/keyframes.js +16 -2
- package/dist/renderer/keyframes.js.map +1 -1
- package/dist/renderer/remote-image.d.ts +9 -7
- package/dist/renderer/remote-image.d.ts.map +1 -1
- package/dist/renderer/remote-image.js +13 -21
- package/dist/renderer/remote-image.js.map +1 -1
- package/dist/renderer/scene-renderer.d.ts +45 -6
- package/dist/renderer/scene-renderer.d.ts.map +1 -1
- package/dist/renderer/scene-renderer.js +203 -65
- package/dist/renderer/scene-renderer.js.map +1 -1
- package/dist/renderer/text-engine.d.ts +24 -5
- package/dist/renderer/text-engine.d.ts.map +1 -1
- package/dist/renderer/text-engine.js +51 -28
- package/dist/renderer/text-engine.js.map +1 -1
- package/package.json +2 -2
- package/server.json +3 -3
|
@@ -5,20 +5,56 @@
|
|
|
5
5
|
import * as fs from 'node:fs/promises';
|
|
6
6
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
7
7
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
8
|
-
import { loadImage } from '@cyanheads/pixoo-toolkit';
|
|
8
|
+
import { loadAnimation, loadImage, NAMED_COLORS, tryResolveColor, } from '@cyanheads/pixoo-toolkit';
|
|
9
|
+
import sharp from 'sharp';
|
|
9
10
|
import { getServerConfig } from '../../../config/server-config.js';
|
|
10
11
|
import { pushKeepingPreview, visibilityNotice } from '../device-push.js';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
12
|
+
import { FinishSchema } from '../finish-schema.js';
|
|
13
|
+
import { finishFrames } from '../../../renderer/finish.js';
|
|
14
|
+
import { autoSavePreview, buildContactSheet, saveGifPreview, savePngPreview, } from '../../../renderer/preview.js';
|
|
15
|
+
import { fetchRemoteImageBytes, isRemoteSource } from '../../../renderer/remote-image.js';
|
|
16
|
+
import { decodeFailureMessage } from '../../../renderer/scene-renderer.js';
|
|
13
17
|
import { getPixooService } from '../../../services/pixoo/pixoo-service.js';
|
|
18
|
+
/** Frames the device plays without turning unstable; a longer source is sampled down to this. */
|
|
19
|
+
const MAX_FRAMES = 40;
|
|
20
|
+
/** Formats the decoder reports that may hold several frames. */
|
|
21
|
+
const ANIMATED_FORMATS = new Set(['gif', 'webp']);
|
|
22
|
+
/** Per-frame speed, in ms, for an animation whose source records no delays. */
|
|
23
|
+
const DEFAULT_SPEED_MS = 150;
|
|
24
|
+
/** The per-frame speed range, in ms, an animation pushes at — as on pixoo_compose_scene. */
|
|
25
|
+
const MIN_SPEED_MS = 10;
|
|
26
|
+
const MAX_SPEED_MS = 2000;
|
|
27
|
+
/**
|
|
28
|
+
* Decode `image` into display-size frames. A source the decoder reports as GIF or WebP
|
|
29
|
+
* loads every frame, sampled evenly down to {@link MAX_FRAMES}; any other format loads
|
|
30
|
+
* as a still. The content decides, not the file extension.
|
|
31
|
+
*/
|
|
32
|
+
async function loadFrames(image, placement) {
|
|
33
|
+
const { format } = await sharp(image).metadata();
|
|
34
|
+
if (ANIMATED_FORMATS.has(format)) {
|
|
35
|
+
return loadAnimation(image, { ...placement, maxFrames: MAX_FRAMES });
|
|
36
|
+
}
|
|
37
|
+
return { frames: [await loadImage(image, placement)], delays: [0], sourceFrames: 1 };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The one per-frame speed that keeps the loop's length: the delays' total over the
|
|
41
|
+
* frame count, rounded and clamped to the device's range. A source with no recorded
|
|
42
|
+
* timing plays at {@link DEFAULT_SPEED_MS}.
|
|
43
|
+
*/
|
|
44
|
+
function loopSpeed(delays) {
|
|
45
|
+
const total = delays.reduce((sum, delay) => sum + delay, 0);
|
|
46
|
+
if (total === 0)
|
|
47
|
+
return DEFAULT_SPEED_MS;
|
|
48
|
+
return Math.min(MAX_SPEED_MS, Math.max(MIN_SPEED_MS, Math.round(total / delays.length)));
|
|
49
|
+
}
|
|
14
50
|
export const pixooPushImage = tool('pixoo_push_image', {
|
|
15
51
|
title: 'pixoo_push_image',
|
|
16
|
-
description: 'Load an image (absolute local path or https URL), resize it to fit the LED grid, and optionally push it to the display. Returns the downsampled result as an image content block so you see exactly what the display received. Nearest-neighbor kernel preserves pixel art; use lanczos3 or mitchell for photos.',
|
|
52
|
+
description: 'Load an image (absolute local path or https URL), resize it to fit the LED grid, and optionally push it to the display. An animated GIF or WebP pushes as an animation of up to 40 frames, sampled evenly from a longer source and played at the speed that keeps its loop length. Returns the downsampled result as an image content block so you see exactly what the display received — a grid of every frame for an animation. Nearest-neighbor kernel preserves pixel art; use lanczos3 or mitchell for photos. finish reduces the result to a small or fixed palette, optionally dithered.',
|
|
17
53
|
annotations: { idempotentHint: true, destructiveHint: false, openWorldHint: true },
|
|
18
54
|
input: z.object({
|
|
19
55
|
source: z
|
|
20
56
|
.string()
|
|
21
|
-
.describe('Absolute local file path or https (not http) URL of the image to display.'),
|
|
57
|
+
.describe('Absolute local file path or https (not http) URL of the image to display. An animated GIF or WebP, whatever its file name, pushes as an animation.'),
|
|
22
58
|
fit: z
|
|
23
59
|
.enum(['contain', 'cover', 'fill'])
|
|
24
60
|
.default('contain')
|
|
@@ -27,6 +63,14 @@ export const pixooPushImage = tool('pixoo_push_image', {
|
|
|
27
63
|
.enum(['nearest', 'lanczos3', 'mitchell'])
|
|
28
64
|
.default('nearest')
|
|
29
65
|
.describe('Resize kernel: nearest for pixel art, lanczos3 for photos, mitchell for a balance.'),
|
|
66
|
+
speed: z
|
|
67
|
+
.number()
|
|
68
|
+
.int()
|
|
69
|
+
.min(MIN_SPEED_MS)
|
|
70
|
+
.max(MAX_SPEED_MS)
|
|
71
|
+
.optional()
|
|
72
|
+
.describe("Milliseconds per frame for an animated source (10–2000). Default: the source's total duration over the pushed frame count, or 150 when it records no delays. A still ignores it."),
|
|
73
|
+
finish: FinishSchema.optional(),
|
|
30
74
|
push: z
|
|
31
75
|
.boolean()
|
|
32
76
|
.default(true)
|
|
@@ -34,6 +78,16 @@ export const pixooPushImage = tool('pixoo_push_image', {
|
|
|
34
78
|
}),
|
|
35
79
|
output: z.object({
|
|
36
80
|
pushed: z.boolean().describe('True when the device acknowledged the push.'),
|
|
81
|
+
frames: z
|
|
82
|
+
.number()
|
|
83
|
+
.describe('Frames rendered and pushed: 1 for a still, 2–40 for an animation.'),
|
|
84
|
+
sourceFrames: z
|
|
85
|
+
.number()
|
|
86
|
+
.describe('Frames in the source before sampling down to 40: 1 for a still.'),
|
|
87
|
+
speed: z
|
|
88
|
+
.number()
|
|
89
|
+
.optional()
|
|
90
|
+
.describe('Milliseconds per frame the animation plays at. Absent for a still.'),
|
|
37
91
|
deviceState: z
|
|
38
92
|
.object({
|
|
39
93
|
reachable: z.boolean().describe('True if device responded.'),
|
|
@@ -56,7 +110,7 @@ export const pixooPushImage = tool('pixoo_push_image', {
|
|
|
56
110
|
outputFiles: z
|
|
57
111
|
.array(z.string())
|
|
58
112
|
.optional()
|
|
59
|
-
.describe('Absolute paths to saved PNG
|
|
113
|
+
.describe('Absolute paths to saved preview files: a PNG for a still, a GIF at the pushed speed for an animation. Present only when PIXOO_OUTPUT_DIR is configured.'),
|
|
60
114
|
}),
|
|
61
115
|
enrichment: {
|
|
62
116
|
notice: z.string().optional().describe('Warning or informational message.'),
|
|
@@ -95,50 +149,70 @@ export const pixooPushImage = tool('pixoo_push_image', {
|
|
|
95
149
|
reason: 'asset_not_found',
|
|
96
150
|
code: JsonRpcErrorCode.NotFound,
|
|
97
151
|
when: 'Image path or URL could not be read.',
|
|
98
|
-
recovery: '
|
|
152
|
+
recovery: 'Pass an absolute path to an existing, readable image file, or a reachable https URL serving 10 MiB or less.',
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
reason: 'invalid_image',
|
|
156
|
+
code: JsonRpcErrorCode.InvalidParams,
|
|
157
|
+
when: 'The source was read but did not decode as an image.',
|
|
158
|
+
recovery: 'The source must be a complete PNG, JPEG, GIF, WebP, AVIF, TIFF, or SVG image; a text file, an HTML page, or a truncated download will not decode.',
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
reason: 'invalid_color',
|
|
162
|
+
code: JsonRpcErrorCode.InvalidParams,
|
|
163
|
+
when: 'A finish palette entry could not be resolved to a color.',
|
|
164
|
+
recovery: 'Use a hex color (#RRGGBB or #RGB, with or without the #) or a case-insensitive named color such as white, orange, or claude.',
|
|
99
165
|
},
|
|
100
166
|
],
|
|
101
167
|
async handler(input, ctx) {
|
|
102
168
|
const cfg = getServerConfig();
|
|
103
169
|
const size = cfg.pixooSize;
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
|
|
170
|
+
// Checked before the source is read: a typo in the palette must not cost a download.
|
|
171
|
+
const unknownColor = input.finish && 'palette' in input.finish
|
|
172
|
+
? input.finish.palette.find((color) => !tryResolveColor(color))
|
|
173
|
+
: undefined;
|
|
174
|
+
if (unknownColor !== undefined) {
|
|
175
|
+
throw ctx.fail('invalid_color', `Unknown color in finish.palette: "${unknownColor}". Valid named colors: ${Object.keys(NAMED_COLORS).join(', ')}.`, ctx.recoveryFor('invalid_color'));
|
|
176
|
+
}
|
|
177
|
+
let image = input.source;
|
|
107
178
|
if (isRemoteSource(input.source)) {
|
|
108
179
|
ctx.log.info('Fetching image from URL', { url: input.source });
|
|
109
|
-
|
|
180
|
+
image = await fetchRemoteImageBytes(input.source, ctx);
|
|
110
181
|
}
|
|
111
182
|
else {
|
|
112
183
|
try {
|
|
113
|
-
await fs.access(input.source);
|
|
184
|
+
await fs.access(input.source, fs.constants.R_OK);
|
|
114
185
|
}
|
|
115
186
|
catch {
|
|
116
|
-
throw ctx.fail('asset_not_found', `Image file not found: "${input.source}". Verify the absolute path is correct.`, { path: input.source, ...ctx.recoveryFor('asset_not_found') });
|
|
187
|
+
throw ctx.fail('asset_not_found', `Image file not found or unreadable: "${input.source}". Verify the absolute path is correct and readable.`, { path: input.source, ...ctx.recoveryFor('asset_not_found') });
|
|
117
188
|
}
|
|
118
189
|
}
|
|
119
|
-
const localPath = tmpPathToCleanup ?? input.source;
|
|
120
190
|
ctx.log.info('Loading and resizing image', { fit: input.fit, kernel: input.kernel });
|
|
121
|
-
|
|
122
|
-
const canvas = await loadImage(localPath, {
|
|
191
|
+
const loaded = await loadFrames(image, {
|
|
123
192
|
size,
|
|
124
193
|
fit: input.fit,
|
|
125
194
|
kernel: input.kernel,
|
|
195
|
+
}).catch((err) => {
|
|
196
|
+
throw ctx.fail('invalid_image', decodeFailureMessage('Image source', input.source, err), { source: input.source, ...ctx.recoveryFor('invalid_image') }, { cause: err });
|
|
126
197
|
});
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
ctx.content.
|
|
198
|
+
const { delays, sourceFrames } = loaded;
|
|
199
|
+
const frames = input.finish ? finishFrames(loaded.frames, input.finish) : loaded.frames;
|
|
200
|
+
const [first] = frames;
|
|
201
|
+
const speed = frames.length > 1 ? (input.speed ?? loopSpeed(delays)) : undefined;
|
|
202
|
+
// The downsampled result (a grid of every frame for an animation) rides content[] as
|
|
203
|
+
// an image block. It is deliberately absent from `output` — routing it through
|
|
204
|
+
// ctx.content carries the base64 once instead of duplicating it into structuredContent.
|
|
205
|
+
ctx.content.image((await buildContactSheet(frames)).data, 'image/png');
|
|
134
206
|
const baseName = `push-image-${Date.now()}`;
|
|
135
|
-
const writePreview = (dir) =>
|
|
207
|
+
const writePreview = (dir) => speed === undefined
|
|
208
|
+
? savePngPreview(first, dir, baseName)
|
|
209
|
+
: saveGifPreview(frames, speed, dir, baseName);
|
|
136
210
|
const outputFiles = await autoSavePreview(writePreview);
|
|
137
211
|
let pushed = false;
|
|
138
212
|
let deviceState;
|
|
139
213
|
if (input.push) {
|
|
140
214
|
const svc = getPixooService();
|
|
141
|
-
deviceState = await pushKeepingPreview(() => svc.pushFrame(
|
|
215
|
+
deviceState = await pushKeepingPreview(() => speed === undefined ? svc.pushFrame(first, ctx) : svc.pushAnimation(frames, speed, ctx), outputFiles, writePreview);
|
|
142
216
|
pushed = true;
|
|
143
217
|
const notice = visibilityNotice(deviceState);
|
|
144
218
|
if (notice)
|
|
@@ -146,13 +220,18 @@ export const pixooPushImage = tool('pixoo_push_image', {
|
|
|
146
220
|
}
|
|
147
221
|
return {
|
|
148
222
|
pushed,
|
|
223
|
+
frames: frames.length,
|
|
224
|
+
sourceFrames,
|
|
225
|
+
...(speed !== undefined && { speed }),
|
|
149
226
|
deviceState,
|
|
150
227
|
outputFiles: outputFiles.length > 0 ? outputFiles : undefined,
|
|
151
228
|
};
|
|
152
229
|
},
|
|
153
230
|
format: (result) => {
|
|
154
231
|
const lines = [];
|
|
155
|
-
|
|
232
|
+
const frames = `**Frames:** ${result.frames} of ${result.sourceFrames} source frame${result.sourceFrames === 1 ? '' : 's'}`;
|
|
233
|
+
const speed = result.speed !== undefined ? ` | **Speed:** ${result.speed} ms per frame` : '';
|
|
234
|
+
lines.push(`**Pushed:** ${result.pushed ? 'Yes' : 'No'} | ${frames}${speed}`);
|
|
156
235
|
if (result.deviceState) {
|
|
157
236
|
const ds = result.deviceState;
|
|
158
237
|
lines.push(`**Device:** ${ds.reachable ? 'Reachable' : 'Unreachable'}` +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pixoo-push-image.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/pixoo-push-image.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,
|
|
1
|
+
{"version":3,"file":"pixoo-push-image.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/pixoo-push-image.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview The `finish` input shared by tools that render an image: reduce it to a
|
|
3
|
+
* palette, with optional dithering, before it reaches the panel. Applied by
|
|
4
|
+
* `renderer/finish`.
|
|
5
|
+
* @module mcp-server/tools/finish-schema
|
|
6
|
+
*/
|
|
7
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
8
|
+
/**
|
|
9
|
+
* Exactly one of `colors` or `palette`, plus `dither` — a union of two closed objects,
|
|
10
|
+
* so each branch advertises its own required field and a call naming both, or neither,
|
|
11
|
+
* fails validation.
|
|
12
|
+
*/
|
|
13
|
+
export declare const FinishSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
14
|
+
colors: z.ZodNumber;
|
|
15
|
+
dither: z.ZodDefault<z.ZodEnum<{
|
|
16
|
+
bayer4: "bayer4";
|
|
17
|
+
"floyd-steinberg": "floyd-steinberg";
|
|
18
|
+
none: "none";
|
|
19
|
+
}>>;
|
|
20
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
21
|
+
palette: z.ZodArray<z.ZodString>;
|
|
22
|
+
dither: z.ZodDefault<z.ZodEnum<{
|
|
23
|
+
bayer4: "bayer4";
|
|
24
|
+
"floyd-steinberg": "floyd-steinberg";
|
|
25
|
+
none: "none";
|
|
26
|
+
}>>;
|
|
27
|
+
}, z.core.$strict>]>;
|
|
28
|
+
//# sourceMappingURL=finish-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finish-schema.d.ts","sourceRoot":"","sources":["../../../src/mcp-server/tools/finish-schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAS3C;;;;GAIG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;oBA0BtB,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview The `finish` input shared by tools that render an image: reduce it to a
|
|
3
|
+
* palette, with optional dithering, before it reaches the panel. Applied by
|
|
4
|
+
* `renderer/finish`.
|
|
5
|
+
* @module mcp-server/tools/finish-schema
|
|
6
|
+
*/
|
|
7
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
8
|
+
const DitherSchema = z
|
|
9
|
+
.enum(['none', 'bayer4', 'floyd-steinberg'])
|
|
10
|
+
.default('none')
|
|
11
|
+
.describe('How palette colors are placed: none maps each pixel to its nearest color; bayer4 mixes the two nearest in an ordered 4×4 pattern; floyd-steinberg diffuses the difference to neighboring pixels, smoothest on photos.');
|
|
12
|
+
/**
|
|
13
|
+
* Exactly one of `colors` or `palette`, plus `dither` — a union of two closed objects,
|
|
14
|
+
* so each branch advertises its own required field and a call naming both, or neither,
|
|
15
|
+
* fails validation.
|
|
16
|
+
*/
|
|
17
|
+
export const FinishSchema = z
|
|
18
|
+
.union([
|
|
19
|
+
z
|
|
20
|
+
.strictObject({
|
|
21
|
+
colors: z
|
|
22
|
+
.number()
|
|
23
|
+
.int()
|
|
24
|
+
.min(2)
|
|
25
|
+
.max(256)
|
|
26
|
+
.describe('Build a palette of at most this many colors (2–256) from the image itself.'),
|
|
27
|
+
dither: DitherSchema,
|
|
28
|
+
})
|
|
29
|
+
.describe('Reduce to a palette built from the image.'),
|
|
30
|
+
z
|
|
31
|
+
.strictObject({
|
|
32
|
+
palette: z
|
|
33
|
+
.array(z.string().describe('Hex color (#RRGGBB or #RGB) or a named color.'))
|
|
34
|
+
.min(1)
|
|
35
|
+
.max(256)
|
|
36
|
+
.describe('Map every pixel to these colors (1–256 entries).'),
|
|
37
|
+
dither: DitherSchema,
|
|
38
|
+
})
|
|
39
|
+
.describe('Reduce to a fixed palette.'),
|
|
40
|
+
])
|
|
41
|
+
.describe('Reduce the image to a palette before it reaches the panel: exactly one of colors (2–256, built from the image) or palette (1–256 hex or named colors), plus dither. Transparent pixels stay unlit and are not counted. The preview shows the finished frame.');
|
|
42
|
+
//# sourceMappingURL=finish-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finish-schema.js","sourceRoot":"","sources":["../../../src/mcp-server/tools/finish-schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAE3C,MAAM,YAAY,GAAG,CAAC;KACnB,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC;KAC3C,OAAO,CAAC,MAAM,CAAC;KACf,QAAQ,CACP,uNAAuN,CACxN,CAAC;AAEJ;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC;KAC1B,KAAK,CAAC;IACL,CAAC;SACE,YAAY,CAAC;QACZ,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,GAAG,CAAC;aACR,QAAQ,CAAC,4EAA4E,CAAC;QACzF,MAAM,EAAE,YAAY;KACrB,CAAC;SACD,QAAQ,CAAC,2CAA2C,CAAC;IACxD,CAAC;SACE,YAAY,CAAC;QACZ,OAAO,EAAE,CAAC;aACP,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC,CAAC;aAC3E,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,GAAG,CAAC;aACR,QAAQ,CAAC,kDAAkD,CAAC;QAC/D,MAAM,EAAE,YAAY;KACrB,CAAC;SACD,QAAQ,CAAC,4BAA4B,CAAC;CAC1C,CAAC;KACD,QAAQ,CACP,8PAA8P,CAC/P,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Palette finishing — reduce a rendered canvas, or every frame of an
|
|
3
|
+
* animation, to a palette with optional dithering through the toolkit's `quantize`.
|
|
4
|
+
* Tool-agnostic: any render path applies a caller's `finish` here, after the load and
|
|
5
|
+
* before the preview, so the preview is exactly the frame the device receives.
|
|
6
|
+
* @module renderer/finish
|
|
7
|
+
*/
|
|
8
|
+
import { Canvas, type QuantizeOptions } from '@cyanheads/pixoo-toolkit';
|
|
9
|
+
/**
|
|
10
|
+
* A palette finish: exactly one of `colors` (build a palette of at most that many colors
|
|
11
|
+
* from the image) or `palette` (map to these colors), plus `dither`. Transparent pixels
|
|
12
|
+
* stay unlit and don't count toward `colors`.
|
|
13
|
+
*/
|
|
14
|
+
export type Finish = QuantizeOptions;
|
|
15
|
+
/**
|
|
16
|
+
* Apply `finish` to one canvas.
|
|
17
|
+
*
|
|
18
|
+
* @returns A new canvas; the input is never mutated.
|
|
19
|
+
* @throws {Error} The toolkit's `Unknown color` error for an unresolvable palette entry.
|
|
20
|
+
*/
|
|
21
|
+
export declare function finishFrame(canvas: Canvas, finish: Finish): Canvas;
|
|
22
|
+
/**
|
|
23
|
+
* Apply `finish` to every frame of an animation. `colors` builds one palette from all
|
|
24
|
+
* the frames' visible pixels together, so the whole loop holds at most that many colors;
|
|
25
|
+
* `palette` and `dither` apply to each frame on its own, so dither error never crosses
|
|
26
|
+
* from one frame into the next.
|
|
27
|
+
*
|
|
28
|
+
* @param frames - Frames of one size, up to 4096 stacked rows in all (64 frames of a
|
|
29
|
+
* 64-pixel panel).
|
|
30
|
+
* @returns New canvases, one per frame; the inputs are never mutated.
|
|
31
|
+
* @throws {Error} The toolkit's `Unknown color` error for an unresolvable palette entry.
|
|
32
|
+
*/
|
|
33
|
+
export declare function finishFrames(frames: readonly Canvas[], finish: Finish): Canvas[];
|
|
34
|
+
//# sourceMappingURL=finish.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finish.d.ts","sourceRoot":"","sources":["../../src/renderer/finish.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,KAAK,eAAe,EAAsB,MAAM,0BAA0B,CAAC;AAE5F;;;;GAIG;AACH,MAAM,MAAM,MAAM,GAAG,eAAe,CAAC;AAErC;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAQhF"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Palette finishing — reduce a rendered canvas, or every frame of an
|
|
3
|
+
* animation, to a palette with optional dithering through the toolkit's `quantize`.
|
|
4
|
+
* Tool-agnostic: any render path applies a caller's `finish` here, after the load and
|
|
5
|
+
* before the preview, so the preview is exactly the frame the device receives.
|
|
6
|
+
* @module renderer/finish
|
|
7
|
+
*/
|
|
8
|
+
import { Canvas, quantize } from '@cyanheads/pixoo-toolkit';
|
|
9
|
+
/**
|
|
10
|
+
* Apply `finish` to one canvas.
|
|
11
|
+
*
|
|
12
|
+
* @returns A new canvas; the input is never mutated.
|
|
13
|
+
* @throws {Error} The toolkit's `Unknown color` error for an unresolvable palette entry.
|
|
14
|
+
*/
|
|
15
|
+
export function finishFrame(canvas, finish) {
|
|
16
|
+
return quantize(canvas, finish);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Apply `finish` to every frame of an animation. `colors` builds one palette from all
|
|
20
|
+
* the frames' visible pixels together, so the whole loop holds at most that many colors;
|
|
21
|
+
* `palette` and `dither` apply to each frame on its own, so dither error never crosses
|
|
22
|
+
* from one frame into the next.
|
|
23
|
+
*
|
|
24
|
+
* @param frames - Frames of one size, up to 4096 stacked rows in all (64 frames of a
|
|
25
|
+
* 64-pixel panel).
|
|
26
|
+
* @returns New canvases, one per frame; the inputs are never mutated.
|
|
27
|
+
* @throws {Error} The toolkit's `Unknown color` error for an unresolvable palette entry.
|
|
28
|
+
*/
|
|
29
|
+
export function finishFrames(frames, finish) {
|
|
30
|
+
if (finish.colors === undefined || frames.length <= 1) {
|
|
31
|
+
return frames.map((frame) => quantize(frame, finish));
|
|
32
|
+
}
|
|
33
|
+
const palette = sharedPalette(frames, finish.colors);
|
|
34
|
+
// Nothing visible to reduce — quantize returns such a frame unchanged too.
|
|
35
|
+
if (palette.length === 0)
|
|
36
|
+
return frames.map((frame) => frame.clone());
|
|
37
|
+
return frames.map((frame) => quantize(frame, { palette, dither: finish.dither ?? 'none' }));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The palette of at most `colors` colors `quantize` builds from every frame's visible
|
|
41
|
+
* pixels at once: the frames stacked into one canvas and reduced without dithering,
|
|
42
|
+
* then the reduced canvas's distinct visible colors read back in raster order.
|
|
43
|
+
*/
|
|
44
|
+
function sharedPalette(frames, colors) {
|
|
45
|
+
const [first] = frames;
|
|
46
|
+
const stack = new Canvas(first.width, first.height * frames.length);
|
|
47
|
+
frames.forEach((frame, k) => {
|
|
48
|
+
stack.buffer.set(frame.buffer, k * frame.buffer.length);
|
|
49
|
+
});
|
|
50
|
+
const buf = quantize(stack, { colors }).buffer;
|
|
51
|
+
const palette = new Map();
|
|
52
|
+
for (let i = 0; i < buf.length; i += 4) {
|
|
53
|
+
if (buf[i + 3] === 0)
|
|
54
|
+
continue;
|
|
55
|
+
const rgb = [buf[i] ?? 0, buf[i + 1] ?? 0, buf[i + 2] ?? 0];
|
|
56
|
+
const key = (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
|
|
57
|
+
if (!palette.has(key))
|
|
58
|
+
palette.set(key, rgb);
|
|
59
|
+
}
|
|
60
|
+
return [...palette.values()];
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=finish.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finish.js","sourceRoot":"","sources":["../../src/renderer/finish.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAwB,QAAQ,EAAY,MAAM,0BAA0B,CAAC;AAS5F;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,MAAc;IACxD,OAAO,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAClC,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAAC,MAAyB,EAAE,MAAc;IACpE,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACtD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACrD,2EAA2E;IAC3E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;IACtE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC;AAC9F,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,MAAyB,EAAE,MAAc;IAC9D,MAAM,CAAC,KAAK,CAAC,GAAG,MAAwC,CAAC;IACzD,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACpE,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1B,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;IAC/C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAe,CAAC;IACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;YAAE,SAAS;QAC/B,MAAM,GAAG,GAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACjE,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACpD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -16,12 +16,16 @@ export declare const EFFECT_NAMES: EffectName[];
|
|
|
16
16
|
* `drift`, default 2. For `pulse` and `twinkle` it is the depth of the opacity dip below 100,
|
|
17
17
|
* on a 0–1 scale: default 0.5 for `pulse` (a 50–100 ramp) and 0.6 for `twinkle` (40–100).
|
|
18
18
|
* `blink`, `fade-in`, and `fade-out` ignore it.
|
|
19
|
+
*
|
|
20
|
+
* `twinkle` jitters each frame's phase by an amount fixed by the frame and `element`, the
|
|
21
|
+
* element's index in the scene, so the flicker is irregular and differs between elements
|
|
22
|
+
* while identical scenes render identically.
|
|
19
23
|
*/
|
|
20
24
|
export declare function compileEffect(name: EffectName, opts: {
|
|
21
25
|
amplitude?: number;
|
|
22
26
|
period?: number;
|
|
23
27
|
phase?: number;
|
|
24
|
-
}, totalFrames: number): KeyframeMap;
|
|
28
|
+
}, totalFrames: number, element?: number): KeyframeMap;
|
|
25
29
|
/** A keyframe's value. */
|
|
26
30
|
type KeyframeValue = KeyframeEntry[1];
|
|
27
31
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyframes.d.ts","sourceRoot":"","sources":["../../src/renderer/keyframes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,oDAAoD;AACpD,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;AAEhE,qDAAqD;AACrD,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;AAE1D,2BAA2B;AAC3B,MAAM,MAAM,UAAU,GAClB,OAAO,GACP,aAAa,GACb,cAAc,GACd,OAAO,GACP,OAAO,GACP,SAAS,GACT,OAAO,GACP,SAAS,GACT,UAAU,CAAC;AAEf,eAAO,MAAM,YAAY,EAAE,UAAU,EAUpC,CAAC;
|
|
1
|
+
{"version":3,"file":"keyframes.d.ts","sourceRoot":"","sources":["../../src/renderer/keyframes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,oDAAoD;AACpD,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;AAEhE,qDAAqD;AACrD,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;AAE1D,2BAA2B;AAC3B,MAAM,MAAM,UAAU,GAClB,OAAO,GACP,aAAa,GACb,cAAc,GACd,OAAO,GACP,OAAO,GACP,SAAS,GACT,OAAO,GACP,SAAS,GACT,UAAU,CAAC;AAEf,eAAO,MAAM,YAAY,EAAE,UAAU,EAUpC,CAAC;AAaF;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE;IACJ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,EACD,WAAW,EAAE,MAAM,EACnB,OAAO,SAAI,GACV,WAAW,CAoFb;AAED,0BAA0B;AAC1B,KAAK,aAAa,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;AA4BtC;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,GAAG,SAAS,CAKrE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,CAY5F;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQ1F;AAED,wEAAwE;AACxE,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,WAAW,GAAG,SAAS,EAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GACtC,MAAM,GAAG,MAAM,GAAG,OAAO,CAG3B"}
|
|
@@ -14,6 +14,16 @@ export const EFFECT_NAMES = [
|
|
|
14
14
|
'fade-in',
|
|
15
15
|
'fade-out',
|
|
16
16
|
];
|
|
17
|
+
/**
|
|
18
|
+
* A fixed value in [0, 1) for one frame of one element: a 32-bit integer hash of the pair,
|
|
19
|
+
* so a render repeats exactly while neighbouring frames and elements still land far apart.
|
|
20
|
+
*/
|
|
21
|
+
function flicker(frame, element) {
|
|
22
|
+
let h = Math.imul(frame, 0x9e3779b1) ^ Math.imul(element + 1, 0x85ebca6b);
|
|
23
|
+
h = Math.imul(h ^ (h >>> 16), 0x7feb352d);
|
|
24
|
+
h = Math.imul(h ^ (h >>> 15), 0x846ca68b);
|
|
25
|
+
return ((h ^ (h >>> 16)) >>> 0) / 2 ** 32;
|
|
26
|
+
}
|
|
17
27
|
/**
|
|
18
28
|
* Compile a named effect preset into a keyframe map.
|
|
19
29
|
*
|
|
@@ -21,8 +31,12 @@ export const EFFECT_NAMES = [
|
|
|
21
31
|
* `drift`, default 2. For `pulse` and `twinkle` it is the depth of the opacity dip below 100,
|
|
22
32
|
* on a 0–1 scale: default 0.5 for `pulse` (a 50–100 ramp) and 0.6 for `twinkle` (40–100).
|
|
23
33
|
* `blink`, `fade-in`, and `fade-out` ignore it.
|
|
34
|
+
*
|
|
35
|
+
* `twinkle` jitters each frame's phase by an amount fixed by the frame and `element`, the
|
|
36
|
+
* element's index in the scene, so the flicker is irregular and differs between elements
|
|
37
|
+
* while identical scenes render identically.
|
|
24
38
|
*/
|
|
25
|
-
export function compileEffect(name, opts, totalFrames) {
|
|
39
|
+
export function compileEffect(name, opts, totalFrames, element = 0) {
|
|
26
40
|
const amp = opts.amplitude ?? 2;
|
|
27
41
|
const period = opts.period ?? totalFrames;
|
|
28
42
|
const phase = opts.phase ?? 0;
|
|
@@ -74,7 +88,7 @@ export function compileEffect(name, opts, totalFrames) {
|
|
|
74
88
|
const frames = [];
|
|
75
89
|
for (let i = 0; i < totalFrames; i++) {
|
|
76
90
|
const t = (i / period + phase) * 2 * Math.PI;
|
|
77
|
-
const brightness = 0.5 + 0.5 * Math.sin(t +
|
|
91
|
+
const brightness = 0.5 + 0.5 * Math.sin(t + flicker(i, element) * 0.3);
|
|
78
92
|
frames.push([i, Math.round(100 - depth + depth * brightness)]);
|
|
79
93
|
}
|
|
80
94
|
return { opacity: frames };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyframes.js","sourceRoot":"","sources":["../../src/renderer/keyframes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAoB7E,MAAM,CAAC,MAAM,YAAY,GAAiB;IACxC,OAAO;IACP,aAAa;IACb,cAAc;IACd,OAAO;IACP,OAAO;IACP,SAAS;IACT,OAAO;IACP,SAAS;IACT,UAAU;CACX,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"keyframes.js","sourceRoot":"","sources":["../../src/renderer/keyframes.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Remote image fetch — downloads an https image
|
|
3
|
-
* toolkit's
|
|
4
|
-
*
|
|
2
|
+
* @fileoverview Remote image fetch — downloads an https image's encoded bytes into
|
|
3
|
+
* memory for the toolkit's image loaders. Shared by the scene renderer's image elements
|
|
4
|
+
* and the pixoo_push_image tool.
|
|
5
5
|
* @module renderer/remote-image
|
|
6
6
|
*/
|
|
7
7
|
import type { Context } from '@cyanheads/mcp-ts-core';
|
|
8
8
|
/** True when the string is a URL rather than a local filesystem path. */
|
|
9
9
|
export declare function isRemoteSource(source: string): boolean;
|
|
10
10
|
/**
|
|
11
|
-
* Fetch an https image and
|
|
12
|
-
*
|
|
11
|
+
* Fetch an https image and return its bytes as served, undecoded. Nothing is written to
|
|
12
|
+
* disk: the caller passes the bytes to the toolkit's loader, where a body that is not an image
|
|
13
|
+
* fails to decode.
|
|
13
14
|
*
|
|
14
15
|
* Private and loopback addresses are deliberately reachable: this server drives a
|
|
15
16
|
* LAN device, so a NAS or local web server is a legitimate image host.
|
|
@@ -18,12 +19,13 @@ export declare function isRemoteSource(source: string): boolean;
|
|
|
18
19
|
* down instead of reading on to the deadline or the byte cap.
|
|
19
20
|
*
|
|
20
21
|
* @throws {McpError} NotFound with `reason: 'asset_not_found'` for a non-https URL,
|
|
21
|
-
* an unreachable or non-2xx endpoint, or a response over {@link MAX_IMAGE_BYTES}.
|
|
22
|
+
* an unreachable or non-2xx endpoint, or a response over {@link MAX_IMAGE_BYTES}. The
|
|
23
|
+
* message names the failure; the recovery is the calling tool's declared one.
|
|
22
24
|
* @throws {McpError} RequestCancelled when `ctx.signal` aborts while the body streams.
|
|
23
25
|
* @throws {McpError} Timeout when the body outlasts {@link FETCH_TIMEOUT_MS}, or when the
|
|
24
26
|
* `ctx.signal` abort is a caller-side deadline (a `TimeoutError` reason). A tool handler
|
|
25
27
|
* still answers the deadline as RequestCancelled: the handler factory settles any throw
|
|
26
28
|
* after the request's signal fired as a cancellation.
|
|
27
29
|
*/
|
|
28
|
-
export declare function
|
|
30
|
+
export declare function fetchRemoteImageBytes(source: string, ctx: Context): Promise<Uint8Array>;
|
|
29
31
|
//# sourceMappingURL=remote-image.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-image.d.ts","sourceRoot":"","sources":["../../src/renderer/remote-image.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"remote-image.d.ts","sourceRoot":"","sources":["../../src/renderer/remote-image.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAUtD,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CAqD7F"}
|