@sealpixel/plugin-filter 1.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @sealpixel/plugin-filter
2
+
3
+ Colour filter presets (grayscale, sepia, vintage, cool, warm) and custom colour matrices. Part of the Sealpixel image editor.
@@ -0,0 +1,31 @@
1
+ import type { OperationBase } from '@sealpixel/core';
2
+ import { type FilterOptions } from './options.js';
3
+ import { type ColorMatrix } from './presets.js';
4
+ export { FILTER_DEFAULT_OPTIONS, type FilterOptions, FilterOptionsSchema, type FilterPresetOption, presetLabelKey, presetMatrix, presetName, } from './options.js';
5
+ export { type ColorMatrix, ColorMatrixSchema, FILTER_PRESETS } from './presets.js';
6
+ export interface FilterDoc {
7
+ /** Preset name, `'custom'` when `matrix` was given directly, or null. */
8
+ preset: string | null;
9
+ matrix: ColorMatrix | null;
10
+ /** 0..1 blend between identity and the matrix. */
11
+ strength: number;
12
+ }
13
+ export interface FilterSetOp extends OperationBase<'filter.set'> {
14
+ /** A preset name from `FILTER_PRESETS`, or `'custom'` with `matrix`, or null to clear. */
15
+ preset: string | null;
16
+ matrix?: ColorMatrix | undefined;
17
+ strength?: number | undefined;
18
+ }
19
+ declare module '@sealpixel/core' {
20
+ interface OperationRegistry {
21
+ 'filter.set': FilterSetOp;
22
+ }
23
+ interface DocumentRegistry {
24
+ filter: FilterDoc;
25
+ }
26
+ }
27
+ export declare const filterSet: import("@sealpixel/core").OperationDef<FilterDoc, FilterSetOp>;
28
+ export declare const filterPlugin: import("@sealpixel/plugin-sdk").ConfigurablePlugin<"filter", FilterDoc, FilterOptions>;
29
+ /** The matrix behind a configured preset, for tools that build ops. */
30
+ export declare function matrixForPreset(options: FilterOptions, name: string): ColorMatrix | null;
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGrD,OAAO,EAGL,KAAK,aAAa,EAInB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,KAAK,WAAW,EAAqC,MAAM,cAAc,CAAC;AAEnF,OAAO,EACL,sBAAsB,EACtB,KAAK,aAAa,EAClB,mBAAmB,EACnB,KAAK,kBAAkB,EACvB,cAAc,EACd,YAAY,EACZ,UAAU,GACX,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,KAAK,WAAW,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnF,MAAM,WAAW,SAAS;IACxB,yEAAyE;IACzE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAY,SAAQ,aAAa,CAAC,YAAY,CAAC;IAC9D,0FAA0F;IAC1F,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,OAAO,QAAQ,iBAAiB,CAAC;IAC/B,UAAU,iBAAiB;QACzB,YAAY,EAAE,WAAW,CAAC;KAC3B;IACD,UAAU,gBAAgB;QACxB,MAAM,EAAE,SAAS,CAAC;KACnB;CACF;AAED,eAAO,MAAM,SAAS,gEA6BpB,CAAC;AAKH,eAAO,MAAM,YAAY,wFA6CvB,CAAC;AAEH,uEAAuE;AACvE,wBAAgB,eAAe,CAAC,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAGxF"}
package/dist/index.js ADDED
@@ -0,0 +1,82 @@
1
+ import { defineOperation, definePlugin } from '@sealpixel/plugin-sdk';
2
+ import { z } from 'zod';
3
+ import { FILTER_DEFAULT_OPTIONS, FILTER_OPTIONS_DESCRIBE, FilterOptionsSchema, presetMatrix, presetName, } from './options.js';
4
+ import { ColorMatrixSchema, FILTER_PRESETS } from './presets.js';
5
+ export { FILTER_DEFAULT_OPTIONS, FilterOptionsSchema, presetLabelKey, presetMatrix, presetName, } from './options.js';
6
+ export { ColorMatrixSchema, FILTER_PRESETS } from './presets.js';
7
+ export const filterSet = defineOperation({
8
+ type: 'filter.set',
9
+ schema: z
10
+ .object({
11
+ type: z.literal('filter.set'),
12
+ id: z.string().min(1),
13
+ at: z.number().optional(),
14
+ preset: z.string().nullable(),
15
+ matrix: ColorMatrixSchema.optional(),
16
+ strength: z.number().min(0).max(1).optional(),
17
+ })
18
+ .strict()
19
+ .refine((op) => (op.preset === null || op.preset === 'custom' ? true : op.preset in FILTER_PRESETS), 'unknown preset')
20
+ .refine((op) => op.preset !== 'custom' || op.matrix !== undefined, 'custom preset needs a matrix'),
21
+ reduce: (slice, op) => {
22
+ if (op.preset === null)
23
+ return { preset: null, matrix: null, strength: op.strength ?? slice.strength };
24
+ const matrix = op.preset === 'custom'
25
+ ? op.matrix
26
+ : FILTER_PRESETS[op.preset];
27
+ return { preset: op.preset, matrix, strength: op.strength ?? slice.strength };
28
+ },
29
+ });
30
+ const sameMatrix = (a, b) => a.every((row, i) => row.every((v, j) => Math.abs(v - b[i][j]) < 1e-9));
31
+ export const filterPlugin = definePlugin({
32
+ id: 'filter',
33
+ version: 1,
34
+ operations: [filterSet],
35
+ initialDocument: { preset: null, matrix: null, strength: 1 },
36
+ stage: { name: 'color', order: 110 },
37
+ toPlan: (doc) => doc.matrix === null || doc.strength === 0
38
+ ? null
39
+ : { matrix: doc.matrix, strength: doc.strength },
40
+ kernel: { kind: 'core' },
41
+ options: {
42
+ schema: FilterOptionsSchema,
43
+ defaults: FILTER_DEFAULT_OPTIONS,
44
+ describe: FILTER_OPTIONS_DESCRIBE,
45
+ },
46
+ initialOps: ({ options }) => {
47
+ if (options.defaultPreset === null)
48
+ return [];
49
+ const preset = options.presets.find((p) => presetName(p) === options.defaultPreset);
50
+ if (!preset)
51
+ return [];
52
+ const op = typeof preset === 'string'
53
+ ? { type: 'filter.set', preset, strength: options.defaultStrength }
54
+ : {
55
+ type: 'filter.set',
56
+ preset: 'custom',
57
+ matrix: preset.matrix,
58
+ strength: options.defaultStrength,
59
+ };
60
+ return [op];
61
+ },
62
+ validate: (op, { options }) => {
63
+ if (op.type !== 'filter.set' || !options.enforce)
64
+ return null;
65
+ const o = op;
66
+ if (o.preset === null)
67
+ return null;
68
+ if (o.preset === 'custom') {
69
+ const ok = options.presets.some((p) => typeof p !== 'string' && o.matrix !== undefined && sameMatrix(p.matrix, o.matrix));
70
+ return ok ? null : 'custom matrix is not one of the configured presets';
71
+ }
72
+ return options.presets.some((p) => presetName(p) === o.preset)
73
+ ? null
74
+ : `preset "${o.preset}" is not offered by this editor`;
75
+ },
76
+ });
77
+ /** The matrix behind a configured preset, for tools that build ops. */
78
+ export function matrixForPreset(options, name) {
79
+ const p = options.presets.find((x) => presetName(x) === name);
80
+ return p ? presetMatrix(p) : null;
81
+ }
82
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import { z } from 'zod';
2
+ import { type ColorMatrix } from './presets.js';
3
+ /** A preset the tool offers. Built-in names refer to `FILTER_PRESETS`; custom ones carry their matrix. */
4
+ export type FilterPresetOption = string | {
5
+ name: string;
6
+ label?: string | undefined;
7
+ matrix: ColorMatrix;
8
+ };
9
+ export interface FilterOptions {
10
+ /**
11
+ * Presets in display order. Built-in names or `{ name, label, matrix }` for
12
+ * a custom matrix. A custom preset is written to the edit log as
13
+ * `preset: 'custom'` with its matrix, so the server needs no options to
14
+ * render it.
15
+ */
16
+ presets: FilterPresetOption[];
17
+ /** Applied when the editor loads a source without a filter op. `null` = none. */
18
+ defaultPreset: string | null;
19
+ /** Initial blend strength for a newly chosen preset, 0..1. */
20
+ defaultStrength: number;
21
+ /** Show a blend strength slider (off by default; defaultStrength applies). */
22
+ strength: boolean;
23
+ /** Bounds of the strength slider. */
24
+ strengthRange: {
25
+ min: number;
26
+ max: number;
27
+ step: number;
28
+ };
29
+ /** Render a live thumbnail per preset instead of a text button. */
30
+ thumbnails: boolean;
31
+ /** Reject edit logs that pick a preset outside `presets` (client and server). Off, options only shape the UI. */
32
+ enforce: boolean;
33
+ }
34
+ export declare const FilterOptionsSchema: z.ZodObject<{
35
+ presets: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
36
+ name: z.ZodString;
37
+ label: z.ZodOptional<z.ZodString>;
38
+ matrix: z.ZodTuple<[z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>, z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>, z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>, z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>], null>;
39
+ }, z.core.$strict>]>>;
40
+ defaultPreset: z.ZodNullable<z.ZodString>;
41
+ defaultStrength: z.ZodNumber;
42
+ strength: z.ZodBoolean;
43
+ strengthRange: z.ZodObject<{
44
+ min: z.ZodNumber;
45
+ max: z.ZodNumber;
46
+ step: z.ZodNumber;
47
+ }, z.core.$strict>;
48
+ thumbnails: z.ZodBoolean;
49
+ enforce: z.ZodBoolean;
50
+ }, z.core.$strict>;
51
+ export declare const FILTER_DEFAULT_OPTIONS: FilterOptions;
52
+ export declare const FILTER_OPTIONS_DESCRIBE: Record<keyof FilterOptions, string>;
53
+ export declare function presetName(p: FilterPresetOption): string;
54
+ /** The matrix a preset option resolves to. */
55
+ export declare function presetMatrix(p: FilterPresetOption): ColorMatrix;
56
+ export declare function presetLabelKey(p: FilterPresetOption): {
57
+ key: string;
58
+ literal?: string;
59
+ };
60
+ //# sourceMappingURL=options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,KAAK,WAAW,EAAqC,MAAM,cAAc,CAAC;AAEnF,0GAA0G;AAC1G,MAAM,MAAM,kBAAkB,GAC1B,MAAM,GACN;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC;AAEtE,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,iFAAiF;IACjF,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,8DAA8D;IAC9D,eAAe,EAAE,MAAM,CAAC;IACxB,8EAA8E;IAC9E,QAAQ,EAAE,OAAO,CAAC;IAClB,qCAAqC;IACrC,aAAa,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1D,mEAAmE;IACnE,UAAU,EAAE,OAAO,CAAC;IACpB,iHAAiH;IACjH,OAAO,EAAE,OAAO,CAAC;CAClB;AAID,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;kBAsC7B,CAAC;AAEJ,eAAO,MAAM,sBAAsB,EAAE,aAQpC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,MAAM,aAAa,EAAE,MAAM,CAWvE,CAAC;AAEF,wBAAgB,UAAU,CAAC,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAExD;AAED,8CAA8C;AAC9C,wBAAgB,YAAY,CAAC,CAAC,EAAE,kBAAkB,GAAG,WAAW,CAE/D;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,kBAAkB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAGvF"}
@@ -0,0 +1,65 @@
1
+ import { z } from 'zod';
2
+ import { ColorMatrixSchema, FILTER_PRESETS } from './presets.js';
3
+ const builtin = Object.keys(FILTER_PRESETS);
4
+ export const FilterOptionsSchema = z
5
+ .object({
6
+ presets: z
7
+ .array(z.union([
8
+ z.string().refine((n) => builtin.includes(n), {
9
+ message: `built-in preset must be one of ${builtin.join(', ')}`,
10
+ }),
11
+ z
12
+ .object({
13
+ name: z
14
+ .string()
15
+ .min(1)
16
+ .refine((n) => n !== 'custom' && !builtin.includes(n), 'custom preset name clashes with a built-in'),
17
+ label: z.string().min(1).optional(),
18
+ matrix: ColorMatrixSchema,
19
+ })
20
+ .strict(),
21
+ ]))
22
+ .min(1),
23
+ defaultPreset: z.string().nullable(),
24
+ defaultStrength: z.number().min(0).max(1),
25
+ strength: z.boolean(),
26
+ strengthRange: z
27
+ .object({ min: z.number().min(0), max: z.number().max(1), step: z.number().positive() })
28
+ .strict()
29
+ .refine((r) => r.min < r.max, 'min must be below max'),
30
+ thumbnails: z.boolean(),
31
+ enforce: z.boolean(),
32
+ })
33
+ .strict()
34
+ .refine((o) => o.defaultPreset === null || o.presets.some((p) => presetName(p) === o.defaultPreset), 'defaultPreset must be one of presets');
35
+ export const FILTER_DEFAULT_OPTIONS = {
36
+ presets: ['grayscale', 'sepia', 'vintage', 'cool', 'warm', 'invert'],
37
+ defaultPreset: null,
38
+ defaultStrength: 1,
39
+ strength: false,
40
+ strengthRange: { min: 0, max: 1, step: 0.01 },
41
+ thumbnails: true,
42
+ enforce: false,
43
+ };
44
+ export const FILTER_OPTIONS_DESCRIBE = {
45
+ presets: 'Presets in display order: built-in names or custom { name, label, matrix }.',
46
+ defaultPreset: 'Preset applied to a freshly loaded image, or null.',
47
+ defaultStrength: 'Blend strength a newly chosen preset starts with (0..1).',
48
+ strength: 'Show a blend strength slider. Off by default: the strength comes from defaultStrength.',
49
+ strengthRange: 'Bounds and step of the strength slider when shown; with enforce, the accepted range.',
50
+ thumbnails: 'Render a live thumbnail per preset instead of a text button. On by default.',
51
+ enforce: 'Reject logs whose preset is not in `presets`; custom presets must match a configured matrix.',
52
+ };
53
+ export function presetName(p) {
54
+ return typeof p === 'string' ? p : p.name;
55
+ }
56
+ /** The matrix a preset option resolves to. */
57
+ export function presetMatrix(p) {
58
+ return typeof p === 'string' ? FILTER_PRESETS[p] : p.matrix;
59
+ }
60
+ export function presetLabelKey(p) {
61
+ if (typeof p === 'string')
62
+ return { key: `filter.${p}` };
63
+ return { key: `filter.${p.name}`, literal: p.label ?? p.name };
64
+ }
65
+ //# sourceMappingURL=options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { z } from 'zod';
2
+ /** 4x5 colour matrix: rows r, g, b, a; columns r, g, b, a, offset. */
3
+ export type ColorMatrix = [
4
+ [
5
+ number,
6
+ number,
7
+ number,
8
+ number,
9
+ number
10
+ ],
11
+ [
12
+ number,
13
+ number,
14
+ number,
15
+ number,
16
+ number
17
+ ],
18
+ [
19
+ number,
20
+ number,
21
+ number,
22
+ number,
23
+ number
24
+ ],
25
+ [
26
+ number,
27
+ number,
28
+ number,
29
+ number,
30
+ number
31
+ ]
32
+ ];
33
+ /** Built-in presets. Values are part of the wire contract: never edit, add new names. */
34
+ export declare const FILTER_PRESETS: Readonly<Record<string, ColorMatrix>>;
35
+ export declare const ColorMatrixSchema: z.ZodTuple<[z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>, z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>, z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>, z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>], null>;
36
+ //# sourceMappingURL=presets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../src/presets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,sEAAsE;AACtE,MAAM,MAAM,WAAW,GAAG;IACxB;QAAC,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;KAAC;IACxC;QAAC,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;KAAC;IACxC;QAAC,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;KAAC;IACxC;QAAC,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;KAAC;CACzC,CAAC;AAIF,yFAAyF;AACzF,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAiBhE,CAAC;AAGF,eAAO,MAAM,iBAAiB,wWAAgC,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { z } from 'zod';
2
+ const A = [0, 0, 0, 1, 0];
3
+ /** Built-in presets. Values are part of the wire contract: never edit, add new names. */
4
+ export const FILTER_PRESETS = {
5
+ grayscale: [
6
+ [0.2126, 0.7152, 0.0722, 0, 0],
7
+ [0.2126, 0.7152, 0.0722, 0, 0],
8
+ [0.2126, 0.7152, 0.0722, 0, 0],
9
+ A,
10
+ ],
11
+ sepia: [[0.393, 0.769, 0.189, 0, 0], [0.349, 0.686, 0.168, 0, 0], [0.272, 0.534, 0.131, 0, 0], A],
12
+ vintage: [
13
+ [0.62, 0.32, 0.06, 0, 0.03],
14
+ [0.22, 0.65, 0.13, 0, 0.02],
15
+ [0.16, 0.24, 0.5, 0, 0.05],
16
+ A,
17
+ ],
18
+ cool: [[0.9, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1.1, 0, 0.02], A],
19
+ warm: [[1.1, 0, 0, 0, 0.02], [0, 1, 0, 0, 0], [0, 0, 0.9, 0, 0], A],
20
+ invert: [[-1, 0, 0, 0, 1], [0, -1, 0, 0, 1], [0, 0, -1, 0, 1], A],
21
+ };
22
+ const row = z.tuple([z.number(), z.number(), z.number(), z.number(), z.number()]);
23
+ export const ColorMatrixSchema = z.tuple([row, row, row, row]);
24
+ //# sourceMappingURL=presets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.js","sourceRoot":"","sources":["../src/presets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAUxB,MAAM,CAAC,GAA6C,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AAEpE,yFAAyF;AACzF,MAAM,CAAC,MAAM,cAAc,GAA0C;IACnE,SAAS,EAAE;QACT,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9B,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9B,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9B,CAAC;KACF;IACD,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IACjG,OAAO,EAAE;QACP,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC;QAC3B,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC;QAC3B,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC;QAC1B,CAAC;KACF;IACD,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IACnE,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IACnE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;CAClE,CAAC;AAEF,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAClF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@sealpixel/plugin-filter",
3
+ "version": "1.0.0-rc.0",
4
+ "description": "Colour filter presets (grayscale, sepia, vintage, cool, warm) and custom colour matrices.",
5
+ "license": "BUSL-1.1",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/9feet/sealpixel.git",
9
+ "directory": "packages/plugins/filter"
10
+ },
11
+ "homepage": "https://docs.sealpixel.dev",
12
+ "bugs": "https://github.com/9feet/sealpixel/issues",
13
+ "type": "module",
14
+ "sideEffects": false,
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "keywords": [
20
+ "sealpixel-plugin"
21
+ ],
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "default": "./dist/index.js"
26
+ },
27
+ "./package.json": "./package.json"
28
+ },
29
+ "scripts": {
30
+ "build": "tsc -p tsconfig.build.json",
31
+ "typecheck": "tsc -p tsconfig.json --noEmit",
32
+ "test": "vitest run"
33
+ },
34
+ "dependencies": {
35
+ "@sealpixel/plugin-sdk": "workspace:*"
36
+ },
37
+ "peerDependencies": {
38
+ "@sealpixel/core": "workspace:*",
39
+ "zod": "^4.0.0"
40
+ },
41
+ "devDependencies": {
42
+ "@sealpixel/config": "workspace:*",
43
+ "@sealpixel/core": "workspace:*",
44
+ "@sealpixel/plugin-finetune": "workspace:*",
45
+ "@types/node": "^24.0.0",
46
+ "typescript": "^5.9.0",
47
+ "vitest": "^4.0.0",
48
+ "zod": "^4.0.0"
49
+ }
50
+ }