@pixerate/editor 0.257.0 → 0.259.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/brushes/contract.d.cts +24 -0
- package/dist/brushes/contract.d.ts +24 -0
- package/dist/brushes/index.cjs +116 -1
- package/dist/brushes/index.d.cts +1 -0
- package/dist/brushes/index.d.ts +1 -0
- package/dist/brushes/index.js +115 -0
- package/dist/paint-editor/collaboration.d.cts +38 -0
- package/dist/paint-editor/collaboration.d.ts +38 -0
- package/dist/paint-editor/controller.d.cts +31 -0
- package/dist/paint-editor/controller.d.ts +31 -0
- package/dist/paint-editor/index.cjs +365 -288
- package/dist/paint-editor/index.js +77 -0
- package/dist/paint-editor/stroke.d.cts +2 -0
- package/dist/paint-editor/stroke.d.ts +2 -0
- package/package.json +1 -1
- package/skills/pixerate-paint-editor/SKILL.md +1 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The brush module as language-neutral contracts (`@pixerate/conformance` `domains/brushes`), so
|
|
3
|
+
* another implementation (the Swift port) ships the same brushes: the brush JSON Schema, the
|
|
4
|
+
* built-in presets and the engine brushes they resolve to, the host profiles and what each host
|
|
5
|
+
* accepts, v1 migrations, the library file format, the library's agent tools and the brush editor
|
|
6
|
+
* sections. `scripts/export-contracts.mjs` writes them; a core test fails when the committed
|
|
7
|
+
* files differ from what this returns.
|
|
8
|
+
*
|
|
9
|
+
* Everything here is data from this module's own functions; nothing depends on the package
|
|
10
|
+
* version, so a release does not change the files.
|
|
11
|
+
*/
|
|
12
|
+
import type { JsonSchema } from '../tools/schema.cjs';
|
|
13
|
+
/** Bumped when a contract file changes shape (not when its data changes). */
|
|
14
|
+
export declare const BRUSH_CONTRACT_FORMAT_VERSION = 1;
|
|
15
|
+
/** JSON Schema of a host profile (`profiles.json`). */
|
|
16
|
+
export declare const BRUSH_PROFILE_JSON_SCHEMA: JsonSchema;
|
|
17
|
+
/** JSON Schema of a brush library file (`pixerate-brushes` version 2). */
|
|
18
|
+
export declare const BRUSH_LIBRARY_FILE_JSON_SCHEMA: JsonSchema;
|
|
19
|
+
/**
|
|
20
|
+
* Every brush contract file, by its path under `domains/brushes/` (plain JSON values). The
|
|
21
|
+
* presets and their resolutions, checks and migrations are what an implementation must reproduce;
|
|
22
|
+
* the schemas and tools are what it must accept and offer.
|
|
23
|
+
*/
|
|
24
|
+
export declare function brushContracts(): Record<string, unknown>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The brush module as language-neutral contracts (`@pixerate/conformance` `domains/brushes`), so
|
|
3
|
+
* another implementation (the Swift port) ships the same brushes: the brush JSON Schema, the
|
|
4
|
+
* built-in presets and the engine brushes they resolve to, the host profiles and what each host
|
|
5
|
+
* accepts, v1 migrations, the library file format, the library's agent tools and the brush editor
|
|
6
|
+
* sections. `scripts/export-contracts.mjs` writes them; a core test fails when the committed
|
|
7
|
+
* files differ from what this returns.
|
|
8
|
+
*
|
|
9
|
+
* Everything here is data from this module's own functions; nothing depends on the package
|
|
10
|
+
* version, so a release does not change the files.
|
|
11
|
+
*/
|
|
12
|
+
import type { JsonSchema } from '../tools/schema.js';
|
|
13
|
+
/** Bumped when a contract file changes shape (not when its data changes). */
|
|
14
|
+
export declare const BRUSH_CONTRACT_FORMAT_VERSION = 1;
|
|
15
|
+
/** JSON Schema of a host profile (`profiles.json`). */
|
|
16
|
+
export declare const BRUSH_PROFILE_JSON_SCHEMA: JsonSchema;
|
|
17
|
+
/** JSON Schema of a brush library file (`pixerate-brushes` version 2). */
|
|
18
|
+
export declare const BRUSH_LIBRARY_FILE_JSON_SCHEMA: JsonSchema;
|
|
19
|
+
/**
|
|
20
|
+
* Every brush contract file, by its path under `domains/brushes/` (plain JSON values). The
|
|
21
|
+
* presets and their resolutions, checks and migrations are what an implementation must reproduce;
|
|
22
|
+
* the schemas and tools are what it must accept and offer.
|
|
23
|
+
*/
|
|
24
|
+
export declare function brushContracts(): Record<string, unknown>;
|
package/dist/brushes/index.cjs
CHANGED
|
@@ -55,6 +55,9 @@ require('../chunk-A2IS7EHE.cjs');
|
|
|
55
55
|
|
|
56
56
|
|
|
57
57
|
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
58
61
|
|
|
59
62
|
|
|
60
63
|
|
|
@@ -280,6 +283,118 @@ function brushLibraryGroups(entries, filter = {}) {
|
|
|
280
283
|
return [...groups.values()].sort((a, b) => order.indexOf(a.id) - order.indexOf(b.id));
|
|
281
284
|
}
|
|
282
285
|
|
|
286
|
+
// src/brushes/contract.ts
|
|
287
|
+
var BRUSH_CONTRACT_FORMAT_VERSION = 1;
|
|
288
|
+
var SUPPORT = { type: "string", enum: ["full", "ignored", "none"], description: "full: rendered; ignored: accepted, painted without it (a warning); none: refused (an error)." };
|
|
289
|
+
var BRUSH_PROFILE_JSON_SCHEMA = {
|
|
290
|
+
type: "object",
|
|
291
|
+
description: "What a host can render (`BrushHostProfile`).",
|
|
292
|
+
properties: {
|
|
293
|
+
id: { type: "string", description: "paint, image, canvas, vector\u2026" },
|
|
294
|
+
name: { type: "string", description: "Display name, used in messages." },
|
|
295
|
+
kinds: { type: "array", items: { type: "string", enum: [..._chunkRSIKDWOPcjs.BRUSH_KINDS] }, description: "Brush kinds it has." },
|
|
296
|
+
tools: { type: "array", items: { type: "string", enum: [..._chunkRSIKDWOPcjs.BRUSH_TOOLS] }, description: "Tools it has (kind tool)." },
|
|
297
|
+
tipShapes: { type: "array", items: { type: "string", enum: [..._chunkRSIKDWOPcjs.BRUSH_TIP_SHAPES] }, description: "Tip shapes it renders." },
|
|
298
|
+
marks: { type: "array", items: { type: "string", enum: [..._chunkRSIKDWOPcjs.BRUSH_MARKS_KINDS] }, description: "Marks kinds it renders." },
|
|
299
|
+
surfaces: { type: "array", items: { type: "string", enum: [..._chunkRSIKDWOPcjs.BRUSH_SURFACES] }, description: "Surfaces it renders." },
|
|
300
|
+
exchange: { ...SUPPORT, description: "Picking paint up and mixing it in." },
|
|
301
|
+
reservoir: { ...SUPPORT, description: "The Mixer Brush reservoir." },
|
|
302
|
+
grain: { ...SUPPORT, description: "Paper grain response." },
|
|
303
|
+
light: { ...SUPPORT, description: "Light paint." },
|
|
304
|
+
motion: { ...SUPPORT, description: "Motion after painting." },
|
|
305
|
+
colours: { type: "array", items: { type: "string", enum: ["solid", "dual", "gradient", "effect"] }, description: "Colour kinds a default colour may be." },
|
|
306
|
+
velocity: { ...SUPPORT, description: "Velocity dynamics." },
|
|
307
|
+
tilt: { ...SUPPORT, description: "Tilt dynamics." }
|
|
308
|
+
},
|
|
309
|
+
required: ["id", "name", "kinds", "tools", "tipShapes", "marks", "surfaces", "exchange", "reservoir", "grain", "light", "motion", "colours", "velocity", "tilt"],
|
|
310
|
+
additionalProperties: false
|
|
311
|
+
};
|
|
312
|
+
var BRUSH_LIBRARY_FILE_JSON_SCHEMA = {
|
|
313
|
+
type: "object",
|
|
314
|
+
description: "A brush library file, as export_brushes writes it. Readers also accept version 1 files (flat engine brushes, migrated) and a bare array of brushes.",
|
|
315
|
+
properties: {
|
|
316
|
+
format: { type: "string", const: "pixerate-brushes", description: 'Always "pixerate-brushes".' },
|
|
317
|
+
version: { type: "integer", const: 2, description: "Always 2." },
|
|
318
|
+
brushes: { type: "array", items: { $ref: "brush.schema.json" }, description: "The brushes, each a facet brush (brush.schema.json)." }
|
|
319
|
+
},
|
|
320
|
+
required: ["format", "version", "brushes"],
|
|
321
|
+
additionalProperties: false
|
|
322
|
+
};
|
|
323
|
+
function migrationInputs() {
|
|
324
|
+
const pick = (id) => _chunkRSIKDWOPcjs.brushToJSON.call(void 0, _chunkRSIKDWOPcjs.BUILTIN_BRUSHES.find((b) => b.id === id));
|
|
325
|
+
return [
|
|
326
|
+
{ id: "plain", name: "Plain" },
|
|
327
|
+
pick("pencil-6b"),
|
|
328
|
+
{ ...pick("soft-pastel"), id: "my-pastel", name: "My pastel", category: "custom", grain: 0.2, tip: { ...pick("soft-pastel").tip, size: 50 } },
|
|
329
|
+
pick("mixer-brush"),
|
|
330
|
+
pick("watercolor-wash"),
|
|
331
|
+
pick("impasto-brush"),
|
|
332
|
+
pick("hair-strands"),
|
|
333
|
+
pick("bristle-round"),
|
|
334
|
+
pick("sticker-stars"),
|
|
335
|
+
pick("rainbow-marker"),
|
|
336
|
+
pick("blender"),
|
|
337
|
+
pick("add-water"),
|
|
338
|
+
pick("spray-can"),
|
|
339
|
+
// Fields an engine never reads are dropped on migration.
|
|
340
|
+
{ ...pick("ink-pen"), id: "ink-with-mixer", name: "Ink with mixer settings", mixer: { wet: 0.9, load: 0.1, mix: 0.9, loadEachStroke: false, cleanEachStroke: false, mixing: "pigment" } }
|
|
341
|
+
];
|
|
342
|
+
}
|
|
343
|
+
function editorSectionFixtures() {
|
|
344
|
+
const ids = ["highlighter", "chalk", "watercolor-wash", "hair-strands", "mixer-brush", "blender", "spray-can"];
|
|
345
|
+
return ids.flatMap(
|
|
346
|
+
(id) => Object.keys(_chunkRSIKDWOPcjs.BRUSH_HOST_PROFILES).map((host) => {
|
|
347
|
+
const brush = _chunkRSIKDWOPcjs.BRUSH_PRESETS.find((b) => b.id === id);
|
|
348
|
+
return { brush: id, host, sections: brushEditorSections(brush, _chunkRSIKDWOPcjs.BRUSH_HOST_PROFILES[host]) };
|
|
349
|
+
})
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
function toolDefinitions() {
|
|
353
|
+
const library = _chunkRSIKDWOPcjs.createBrushLibrary.call(void 0, );
|
|
354
|
+
const toolsFor = (host) => _chunkMQGQTKVWcjs.createBrushLibraryTools.call(void 0, library, { profile: _chunkRSIKDWOPcjs.BRUSH_HOST_PROFILES[host], renderPreview: () => ({ data: "", mimeType: "image/png" }) });
|
|
355
|
+
return {
|
|
356
|
+
tools: toolsFor("paint").map((t) => ({ name: t.name, title: t.title, description: t.description, inputSchema: t.inputSchema, annotations: t.annotations })),
|
|
357
|
+
hosts: Object.fromEntries(Object.keys(_chunkRSIKDWOPcjs.BRUSH_HOST_PROFILES).map((host) => [host, toolsFor(host).map((t) => t.name)]))
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
function brushContracts() {
|
|
361
|
+
const presets = _chunkRSIKDWOPcjs.BRUSH_PRESETS.map((b) => JSON.parse(JSON.stringify(b)));
|
|
362
|
+
const resolved = _chunkRSIKDWOPcjs.BRUSH_PRESETS.map((b) => ({ id: b.id, engine: _chunkRSIKDWOPcjs.resolveEngine.call(void 0, b), category: _chunkRSIKDWOPcjs.resolveCategory.call(void 0, b), brush: _chunkRSIKDWOPcjs.brushToJSON.call(void 0, _chunkRSIKDWOPcjs.resolveBrush.call(void 0, b)) }));
|
|
363
|
+
const profiles = Object.values(_chunkRSIKDWOPcjs.BRUSH_HOST_PROFILES);
|
|
364
|
+
const checks = _chunkRSIKDWOPcjs.BRUSH_PRESETS.map((b) => ({
|
|
365
|
+
id: b.id,
|
|
366
|
+
hosts: Object.fromEntries(profiles.map((p) => {
|
|
367
|
+
const c = _chunkRSIKDWOPcjs.checkBrush.call(void 0, b, p);
|
|
368
|
+
return [p.id, { ok: c.ok, issues: c.issues.map(({ facet, severity }) => ({ facet, severity })) }];
|
|
369
|
+
}))
|
|
370
|
+
}));
|
|
371
|
+
const migrations = migrationInputs().map((input) => ({ input, output: _chunkRSIKDWOPcjs.migrateBrushV1.call(void 0, input), resolved: _chunkRSIKDWOPcjs.brushToJSON.call(void 0, _chunkRSIKDWOPcjs.resolveBrush.call(void 0, _chunkRSIKDWOPcjs.migrateBrushV1.call(void 0, input))), engine: _chunkRSIKDWOPcjs.normalizePaintBrush.call(void 0, input).engine }));
|
|
372
|
+
const files = {
|
|
373
|
+
"brush.schema.json": { $schema: "https://json-schema.org/draft/2020-12/schema", $id: "brush.schema.json", ..._chunkRSIKDWOPcjs.BRUSH_JSON_SCHEMA },
|
|
374
|
+
"profile.schema.json": { $schema: "https://json-schema.org/draft/2020-12/schema", $id: "profile.schema.json", ...BRUSH_PROFILE_JSON_SCHEMA },
|
|
375
|
+
"library-file.schema.json": { $schema: "https://json-schema.org/draft/2020-12/schema", $id: "library-file.schema.json", ...BRUSH_LIBRARY_FILE_JSON_SCHEMA },
|
|
376
|
+
"presets.json": presets,
|
|
377
|
+
"resolved.json": resolved,
|
|
378
|
+
"profiles.json": profiles,
|
|
379
|
+
"checks.json": checks,
|
|
380
|
+
"migrations.json": migrations,
|
|
381
|
+
"tools.json": toolDefinitions(),
|
|
382
|
+
"editor-sections.json": editorSectionFixtures()
|
|
383
|
+
};
|
|
384
|
+
files["manifest.json"] = {
|
|
385
|
+
domain: "brushes",
|
|
386
|
+
formatVersion: BRUSH_CONTRACT_FORMAT_VERSION,
|
|
387
|
+
limits: { maxPalette: _chunkRSIKDWOPcjs.MAX_BRUSH_PALETTE },
|
|
388
|
+
counts: { presets: presets.length, profiles: profiles.length, migrations: migrations.length, editorSections: files["editor-sections.json"].length },
|
|
389
|
+
files: Object.keys(files).sort()
|
|
390
|
+
};
|
|
391
|
+
return files;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
|
|
283
398
|
|
|
284
399
|
|
|
285
400
|
|
|
@@ -322,4 +437,4 @@ function brushLibraryGroups(entries, filter = {}) {
|
|
|
322
437
|
|
|
323
438
|
|
|
324
439
|
|
|
325
|
-
exports.BRUSH_FACET_SCHEMAS = _chunkRSIKDWOPcjs.BRUSH_FACET_SCHEMAS; exports.BRUSH_HOST_PROFILES = _chunkRSIKDWOPcjs.BRUSH_HOST_PROFILES; exports.BRUSH_JSON_SCHEMA = _chunkRSIKDWOPcjs.BRUSH_JSON_SCHEMA; exports.BRUSH_KINDS = _chunkRSIKDWOPcjs.BRUSH_KINDS; exports.BRUSH_MARKS_KINDS = _chunkRSIKDWOPcjs.BRUSH_MARKS_KINDS; exports.BRUSH_MEDIA = _chunkRSIKDWOPcjs.BRUSH_MEDIA; exports.BRUSH_PATCH_PROPERTIES = _chunkMQGQTKVWcjs.BRUSH_PATCH_PROPERTIES; exports.BRUSH_PRESETS = _chunkRSIKDWOPcjs.BRUSH_PRESETS; exports.BRUSH_SURFACES = _chunkRSIKDWOPcjs.BRUSH_SURFACES; exports.BRUSH_TIP_SHAPES = _chunkRSIKDWOPcjs.BRUSH_TIP_SHAPES; exports.BRUSH_TOOLS = _chunkRSIKDWOPcjs.BRUSH_TOOLS; exports.BRUSH_UNSET_PROPERTY = _chunkMQGQTKVWcjs.BRUSH_UNSET_PROPERTY; exports.BRUSH_WORD = _chunkRSIKDWOPcjs.BRUSH_WORD; exports.BrushLibraryError = _chunkRSIKDWOPcjs.BrushLibraryError; exports.CANVAS_PROFILE = _chunkRSIKDWOPcjs.CANVAS_PROFILE; exports.IMAGE_PROFILE = _chunkRSIKDWOPcjs.IMAGE_PROFILE; exports.MAX_BRUSH_PALETTE = _chunkRSIKDWOPcjs.MAX_BRUSH_PALETTE; exports.PAINT_PROFILE = _chunkRSIKDWOPcjs.PAINT_PROFILE; exports.UNSETTABLE_BRUSH_FACETS = _chunkMQGQTKVWcjs.UNSETTABLE_BRUSH_FACETS; exports.VECTOR_PROFILE = _chunkRSIKDWOPcjs.VECTOR_PROFILE; exports.WET_BRUSH_TOOLS = _chunkRSIKDWOPcjs.WET_BRUSH_TOOLS; exports.brushColourHex = _chunkLRTR4ASZcjs.brushColourHex; exports.brushColourKind = _chunkRSIKDWOPcjs.brushColourKind; exports.brushEditorSections = brushEditorSections; exports.brushLibraryGroups = brushLibraryGroups; exports.changedBrushPaths = _chunkMQGQTKVWcjs.changedBrushPaths; exports.checkBrush = _chunkRSIKDWOPcjs.checkBrush; exports.createBrushLibrary = _chunkRSIKDWOPcjs.createBrushLibrary; exports.createBrushLibraryToolProvider = _chunkMQGQTKVWcjs.createBrushLibraryToolProvider; exports.createBrushLibraryTools = _chunkMQGQTKVWcjs.createBrushLibraryTools; exports.degrade = _chunkRSIKDWOPcjs.degrade; exports.listPresets = _chunkRSIKDWOPcjs.listPresets; exports.mergeBrushPatch = _chunkMQGQTKVWcjs.mergeBrushPatch; exports.migrateBrushV1 = _chunkRSIKDWOPcjs.migrateBrushV1; exports.normalizeBrushSpec = _chunkRSIKDWOPcjs.normalizeBrushSpec; exports.parseBrushLibrary = _chunkRSIKDWOPcjs.parseBrushLibrary2; exports.resolveBrush = _chunkRSIKDWOPcjs.resolveBrush; exports.resolveCategory = _chunkRSIKDWOPcjs.resolveCategory; exports.resolveEngine = _chunkRSIKDWOPcjs.resolveEngine; exports.resolveWetMedium = _chunkRSIKDWOPcjs.resolveWetMedium; exports.setBrushEditorValue = setBrushEditorValue; exports.snapshotBrushLibrary = _chunkRSIKDWOPcjs.snapshotBrushLibrary;
|
|
440
|
+
exports.BRUSH_CONTRACT_FORMAT_VERSION = BRUSH_CONTRACT_FORMAT_VERSION; exports.BRUSH_FACET_SCHEMAS = _chunkRSIKDWOPcjs.BRUSH_FACET_SCHEMAS; exports.BRUSH_HOST_PROFILES = _chunkRSIKDWOPcjs.BRUSH_HOST_PROFILES; exports.BRUSH_JSON_SCHEMA = _chunkRSIKDWOPcjs.BRUSH_JSON_SCHEMA; exports.BRUSH_KINDS = _chunkRSIKDWOPcjs.BRUSH_KINDS; exports.BRUSH_LIBRARY_FILE_JSON_SCHEMA = BRUSH_LIBRARY_FILE_JSON_SCHEMA; exports.BRUSH_MARKS_KINDS = _chunkRSIKDWOPcjs.BRUSH_MARKS_KINDS; exports.BRUSH_MEDIA = _chunkRSIKDWOPcjs.BRUSH_MEDIA; exports.BRUSH_PATCH_PROPERTIES = _chunkMQGQTKVWcjs.BRUSH_PATCH_PROPERTIES; exports.BRUSH_PRESETS = _chunkRSIKDWOPcjs.BRUSH_PRESETS; exports.BRUSH_PROFILE_JSON_SCHEMA = BRUSH_PROFILE_JSON_SCHEMA; exports.BRUSH_SURFACES = _chunkRSIKDWOPcjs.BRUSH_SURFACES; exports.BRUSH_TIP_SHAPES = _chunkRSIKDWOPcjs.BRUSH_TIP_SHAPES; exports.BRUSH_TOOLS = _chunkRSIKDWOPcjs.BRUSH_TOOLS; exports.BRUSH_UNSET_PROPERTY = _chunkMQGQTKVWcjs.BRUSH_UNSET_PROPERTY; exports.BRUSH_WORD = _chunkRSIKDWOPcjs.BRUSH_WORD; exports.BrushLibraryError = _chunkRSIKDWOPcjs.BrushLibraryError; exports.CANVAS_PROFILE = _chunkRSIKDWOPcjs.CANVAS_PROFILE; exports.IMAGE_PROFILE = _chunkRSIKDWOPcjs.IMAGE_PROFILE; exports.MAX_BRUSH_PALETTE = _chunkRSIKDWOPcjs.MAX_BRUSH_PALETTE; exports.PAINT_PROFILE = _chunkRSIKDWOPcjs.PAINT_PROFILE; exports.UNSETTABLE_BRUSH_FACETS = _chunkMQGQTKVWcjs.UNSETTABLE_BRUSH_FACETS; exports.VECTOR_PROFILE = _chunkRSIKDWOPcjs.VECTOR_PROFILE; exports.WET_BRUSH_TOOLS = _chunkRSIKDWOPcjs.WET_BRUSH_TOOLS; exports.brushColourHex = _chunkLRTR4ASZcjs.brushColourHex; exports.brushColourKind = _chunkRSIKDWOPcjs.brushColourKind; exports.brushContracts = brushContracts; exports.brushEditorSections = brushEditorSections; exports.brushLibraryGroups = brushLibraryGroups; exports.changedBrushPaths = _chunkMQGQTKVWcjs.changedBrushPaths; exports.checkBrush = _chunkRSIKDWOPcjs.checkBrush; exports.createBrushLibrary = _chunkRSIKDWOPcjs.createBrushLibrary; exports.createBrushLibraryToolProvider = _chunkMQGQTKVWcjs.createBrushLibraryToolProvider; exports.createBrushLibraryTools = _chunkMQGQTKVWcjs.createBrushLibraryTools; exports.degrade = _chunkRSIKDWOPcjs.degrade; exports.listPresets = _chunkRSIKDWOPcjs.listPresets; exports.mergeBrushPatch = _chunkMQGQTKVWcjs.mergeBrushPatch; exports.migrateBrushV1 = _chunkRSIKDWOPcjs.migrateBrushV1; exports.normalizeBrushSpec = _chunkRSIKDWOPcjs.normalizeBrushSpec; exports.parseBrushLibrary = _chunkRSIKDWOPcjs.parseBrushLibrary2; exports.resolveBrush = _chunkRSIKDWOPcjs.resolveBrush; exports.resolveCategory = _chunkRSIKDWOPcjs.resolveCategory; exports.resolveEngine = _chunkRSIKDWOPcjs.resolveEngine; exports.resolveWetMedium = _chunkRSIKDWOPcjs.resolveWetMedium; exports.setBrushEditorValue = setBrushEditorValue; exports.snapshotBrushLibrary = _chunkRSIKDWOPcjs.snapshotBrushLibrary;
|
package/dist/brushes/index.d.cts
CHANGED
|
@@ -15,6 +15,7 @@ export { resolveBrush, resolveCategory, resolveEngine, resolveWetMedium, type Re
|
|
|
15
15
|
export { migrateBrushV1 } from './migrate.cjs';
|
|
16
16
|
export { BRUSH_PRESETS } from './presets.cjs';
|
|
17
17
|
export { brushColourHex } from './colour.cjs';
|
|
18
|
+
export { BRUSH_CONTRACT_FORMAT_VERSION, BRUSH_LIBRARY_FILE_JSON_SCHEMA, BRUSH_PROFILE_JSON_SCHEMA, brushContracts } from './contract.cjs';
|
|
18
19
|
export { BRUSH_HOST_PROFILES, brushColourKind, CANVAS_PROFILE, checkBrush, degrade, IMAGE_PROFILE, listPresets, PAINT_PROFILE, VECTOR_PROFILE, type BrushCheck, type BrushColourKind, type BrushHostProfile, type BrushIssue, type BrushSupport, type DegradedBrush } from './profiles.cjs';
|
|
19
20
|
export { BrushLibraryError, createBrushLibrary, parseBrushLibrary, snapshotBrushLibrary, type BrushFilter, type BrushLibrary, type BrushLibraryEntry, type BrushLibraryErrorCode, type BrushLibraryFile, type BrushLibrarySnapshot, type BrushLibraryOptions, type ImportBrushesResult, type SaveBrushResult, } from './library.cjs';
|
|
20
21
|
export { BRUSH_PATCH_PROPERTIES, BRUSH_UNSET_PROPERTY, changedBrushPaths, mergeBrushPatch, UNSETTABLE_BRUSH_FACETS, type BrushPatch, type UnsettableBrushFacet } from './patch.cjs';
|
package/dist/brushes/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export { resolveBrush, resolveCategory, resolveEngine, resolveWetMedium, type Re
|
|
|
15
15
|
export { migrateBrushV1 } from './migrate.js';
|
|
16
16
|
export { BRUSH_PRESETS } from './presets.js';
|
|
17
17
|
export { brushColourHex } from './colour.js';
|
|
18
|
+
export { BRUSH_CONTRACT_FORMAT_VERSION, BRUSH_LIBRARY_FILE_JSON_SCHEMA, BRUSH_PROFILE_JSON_SCHEMA, brushContracts } from './contract.js';
|
|
18
19
|
export { BRUSH_HOST_PROFILES, brushColourKind, CANVAS_PROFILE, checkBrush, degrade, IMAGE_PROFILE, listPresets, PAINT_PROFILE, VECTOR_PROFILE, type BrushCheck, type BrushColourKind, type BrushHostProfile, type BrushIssue, type BrushSupport, type DegradedBrush } from './profiles.js';
|
|
19
20
|
export { BrushLibraryError, createBrushLibrary, parseBrushLibrary, snapshotBrushLibrary, type BrushFilter, type BrushLibrary, type BrushLibraryEntry, type BrushLibraryErrorCode, type BrushLibraryFile, type BrushLibrarySnapshot, type BrushLibraryOptions, type ImportBrushesResult, type SaveBrushResult, } from './library.js';
|
|
20
21
|
export { BRUSH_PATCH_PROPERTIES, BRUSH_UNSET_PROPERTY, changedBrushPaths, mergeBrushPatch, UNSETTABLE_BRUSH_FACETS, type BrushPatch, type UnsettableBrushFacet } from './patch.js';
|
package/dist/brushes/index.js
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
BRUSH_TIP_SHAPES,
|
|
29
29
|
BRUSH_TOOLS,
|
|
30
30
|
BRUSH_WORD,
|
|
31
|
+
BUILTIN_BRUSHES,
|
|
31
32
|
BrushLibraryError,
|
|
32
33
|
CANVAS_PROFILE,
|
|
33
34
|
DOT_ROTATIONS,
|
|
@@ -45,6 +46,7 @@ import {
|
|
|
45
46
|
WET_BRUSH_TOOLS,
|
|
46
47
|
WET_MEDIA,
|
|
47
48
|
brushColourKind,
|
|
49
|
+
brushToJSON,
|
|
48
50
|
checkBrush,
|
|
49
51
|
createBrushLibrary,
|
|
50
52
|
degrade,
|
|
@@ -52,6 +54,7 @@ import {
|
|
|
52
54
|
listPresets,
|
|
53
55
|
migrateBrushV1,
|
|
54
56
|
normalizeBrushSpec,
|
|
57
|
+
normalizePaintBrush,
|
|
55
58
|
parseBrushLibrary2 as parseBrushLibrary,
|
|
56
59
|
resolveBrush,
|
|
57
60
|
resolveCategory,
|
|
@@ -279,15 +282,126 @@ function brushLibraryGroups(entries, filter = {}) {
|
|
|
279
282
|
const order = ["dry", "ink", "paint", "spray", "other", "tools"];
|
|
280
283
|
return [...groups.values()].sort((a, b) => order.indexOf(a.id) - order.indexOf(b.id));
|
|
281
284
|
}
|
|
285
|
+
|
|
286
|
+
// src/brushes/contract.ts
|
|
287
|
+
var BRUSH_CONTRACT_FORMAT_VERSION = 1;
|
|
288
|
+
var SUPPORT = { type: "string", enum: ["full", "ignored", "none"], description: "full: rendered; ignored: accepted, painted without it (a warning); none: refused (an error)." };
|
|
289
|
+
var BRUSH_PROFILE_JSON_SCHEMA = {
|
|
290
|
+
type: "object",
|
|
291
|
+
description: "What a host can render (`BrushHostProfile`).",
|
|
292
|
+
properties: {
|
|
293
|
+
id: { type: "string", description: "paint, image, canvas, vector\u2026" },
|
|
294
|
+
name: { type: "string", description: "Display name, used in messages." },
|
|
295
|
+
kinds: { type: "array", items: { type: "string", enum: [...BRUSH_KINDS] }, description: "Brush kinds it has." },
|
|
296
|
+
tools: { type: "array", items: { type: "string", enum: [...BRUSH_TOOLS] }, description: "Tools it has (kind tool)." },
|
|
297
|
+
tipShapes: { type: "array", items: { type: "string", enum: [...BRUSH_TIP_SHAPES] }, description: "Tip shapes it renders." },
|
|
298
|
+
marks: { type: "array", items: { type: "string", enum: [...BRUSH_MARKS_KINDS] }, description: "Marks kinds it renders." },
|
|
299
|
+
surfaces: { type: "array", items: { type: "string", enum: [...BRUSH_SURFACES] }, description: "Surfaces it renders." },
|
|
300
|
+
exchange: { ...SUPPORT, description: "Picking paint up and mixing it in." },
|
|
301
|
+
reservoir: { ...SUPPORT, description: "The Mixer Brush reservoir." },
|
|
302
|
+
grain: { ...SUPPORT, description: "Paper grain response." },
|
|
303
|
+
light: { ...SUPPORT, description: "Light paint." },
|
|
304
|
+
motion: { ...SUPPORT, description: "Motion after painting." },
|
|
305
|
+
colours: { type: "array", items: { type: "string", enum: ["solid", "dual", "gradient", "effect"] }, description: "Colour kinds a default colour may be." },
|
|
306
|
+
velocity: { ...SUPPORT, description: "Velocity dynamics." },
|
|
307
|
+
tilt: { ...SUPPORT, description: "Tilt dynamics." }
|
|
308
|
+
},
|
|
309
|
+
required: ["id", "name", "kinds", "tools", "tipShapes", "marks", "surfaces", "exchange", "reservoir", "grain", "light", "motion", "colours", "velocity", "tilt"],
|
|
310
|
+
additionalProperties: false
|
|
311
|
+
};
|
|
312
|
+
var BRUSH_LIBRARY_FILE_JSON_SCHEMA = {
|
|
313
|
+
type: "object",
|
|
314
|
+
description: "A brush library file, as export_brushes writes it. Readers also accept version 1 files (flat engine brushes, migrated) and a bare array of brushes.",
|
|
315
|
+
properties: {
|
|
316
|
+
format: { type: "string", const: "pixerate-brushes", description: 'Always "pixerate-brushes".' },
|
|
317
|
+
version: { type: "integer", const: 2, description: "Always 2." },
|
|
318
|
+
brushes: { type: "array", items: { $ref: "brush.schema.json" }, description: "The brushes, each a facet brush (brush.schema.json)." }
|
|
319
|
+
},
|
|
320
|
+
required: ["format", "version", "brushes"],
|
|
321
|
+
additionalProperties: false
|
|
322
|
+
};
|
|
323
|
+
function migrationInputs() {
|
|
324
|
+
const pick = (id) => brushToJSON(BUILTIN_BRUSHES.find((b) => b.id === id));
|
|
325
|
+
return [
|
|
326
|
+
{ id: "plain", name: "Plain" },
|
|
327
|
+
pick("pencil-6b"),
|
|
328
|
+
{ ...pick("soft-pastel"), id: "my-pastel", name: "My pastel", category: "custom", grain: 0.2, tip: { ...pick("soft-pastel").tip, size: 50 } },
|
|
329
|
+
pick("mixer-brush"),
|
|
330
|
+
pick("watercolor-wash"),
|
|
331
|
+
pick("impasto-brush"),
|
|
332
|
+
pick("hair-strands"),
|
|
333
|
+
pick("bristle-round"),
|
|
334
|
+
pick("sticker-stars"),
|
|
335
|
+
pick("rainbow-marker"),
|
|
336
|
+
pick("blender"),
|
|
337
|
+
pick("add-water"),
|
|
338
|
+
pick("spray-can"),
|
|
339
|
+
// Fields an engine never reads are dropped on migration.
|
|
340
|
+
{ ...pick("ink-pen"), id: "ink-with-mixer", name: "Ink with mixer settings", mixer: { wet: 0.9, load: 0.1, mix: 0.9, loadEachStroke: false, cleanEachStroke: false, mixing: "pigment" } }
|
|
341
|
+
];
|
|
342
|
+
}
|
|
343
|
+
function editorSectionFixtures() {
|
|
344
|
+
const ids = ["highlighter", "chalk", "watercolor-wash", "hair-strands", "mixer-brush", "blender", "spray-can"];
|
|
345
|
+
return ids.flatMap(
|
|
346
|
+
(id) => Object.keys(BRUSH_HOST_PROFILES).map((host) => {
|
|
347
|
+
const brush = BRUSH_PRESETS.find((b) => b.id === id);
|
|
348
|
+
return { brush: id, host, sections: brushEditorSections(brush, BRUSH_HOST_PROFILES[host]) };
|
|
349
|
+
})
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
function toolDefinitions() {
|
|
353
|
+
const library = createBrushLibrary();
|
|
354
|
+
const toolsFor = (host) => createBrushLibraryTools(library, { profile: BRUSH_HOST_PROFILES[host], renderPreview: () => ({ data: "", mimeType: "image/png" }) });
|
|
355
|
+
return {
|
|
356
|
+
tools: toolsFor("paint").map((t) => ({ name: t.name, title: t.title, description: t.description, inputSchema: t.inputSchema, annotations: t.annotations })),
|
|
357
|
+
hosts: Object.fromEntries(Object.keys(BRUSH_HOST_PROFILES).map((host) => [host, toolsFor(host).map((t) => t.name)]))
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
function brushContracts() {
|
|
361
|
+
const presets = BRUSH_PRESETS.map((b) => JSON.parse(JSON.stringify(b)));
|
|
362
|
+
const resolved = BRUSH_PRESETS.map((b) => ({ id: b.id, engine: resolveEngine(b), category: resolveCategory(b), brush: brushToJSON(resolveBrush(b)) }));
|
|
363
|
+
const profiles = Object.values(BRUSH_HOST_PROFILES);
|
|
364
|
+
const checks = BRUSH_PRESETS.map((b) => ({
|
|
365
|
+
id: b.id,
|
|
366
|
+
hosts: Object.fromEntries(profiles.map((p) => {
|
|
367
|
+
const c = checkBrush(b, p);
|
|
368
|
+
return [p.id, { ok: c.ok, issues: c.issues.map(({ facet, severity }) => ({ facet, severity })) }];
|
|
369
|
+
}))
|
|
370
|
+
}));
|
|
371
|
+
const migrations = migrationInputs().map((input) => ({ input, output: migrateBrushV1(input), resolved: brushToJSON(resolveBrush(migrateBrushV1(input))), engine: normalizePaintBrush(input).engine }));
|
|
372
|
+
const files = {
|
|
373
|
+
"brush.schema.json": { $schema: "https://json-schema.org/draft/2020-12/schema", $id: "brush.schema.json", ...BRUSH_JSON_SCHEMA },
|
|
374
|
+
"profile.schema.json": { $schema: "https://json-schema.org/draft/2020-12/schema", $id: "profile.schema.json", ...BRUSH_PROFILE_JSON_SCHEMA },
|
|
375
|
+
"library-file.schema.json": { $schema: "https://json-schema.org/draft/2020-12/schema", $id: "library-file.schema.json", ...BRUSH_LIBRARY_FILE_JSON_SCHEMA },
|
|
376
|
+
"presets.json": presets,
|
|
377
|
+
"resolved.json": resolved,
|
|
378
|
+
"profiles.json": profiles,
|
|
379
|
+
"checks.json": checks,
|
|
380
|
+
"migrations.json": migrations,
|
|
381
|
+
"tools.json": toolDefinitions(),
|
|
382
|
+
"editor-sections.json": editorSectionFixtures()
|
|
383
|
+
};
|
|
384
|
+
files["manifest.json"] = {
|
|
385
|
+
domain: "brushes",
|
|
386
|
+
formatVersion: BRUSH_CONTRACT_FORMAT_VERSION,
|
|
387
|
+
limits: { maxPalette: MAX_BRUSH_PALETTE },
|
|
388
|
+
counts: { presets: presets.length, profiles: profiles.length, migrations: migrations.length, editorSections: files["editor-sections.json"].length },
|
|
389
|
+
files: Object.keys(files).sort()
|
|
390
|
+
};
|
|
391
|
+
return files;
|
|
392
|
+
}
|
|
282
393
|
export {
|
|
394
|
+
BRUSH_CONTRACT_FORMAT_VERSION,
|
|
283
395
|
BRUSH_FACET_SCHEMAS,
|
|
284
396
|
BRUSH_HOST_PROFILES,
|
|
285
397
|
BRUSH_JSON_SCHEMA,
|
|
286
398
|
BRUSH_KINDS,
|
|
399
|
+
BRUSH_LIBRARY_FILE_JSON_SCHEMA,
|
|
287
400
|
BRUSH_MARKS_KINDS,
|
|
288
401
|
BRUSH_MEDIA,
|
|
289
402
|
BRUSH_PATCH_PROPERTIES,
|
|
290
403
|
BRUSH_PRESETS,
|
|
404
|
+
BRUSH_PROFILE_JSON_SCHEMA,
|
|
291
405
|
BRUSH_SURFACES,
|
|
292
406
|
BRUSH_TIP_SHAPES,
|
|
293
407
|
BRUSH_TOOLS,
|
|
@@ -303,6 +417,7 @@ export {
|
|
|
303
417
|
WET_BRUSH_TOOLS,
|
|
304
418
|
brushColourHex,
|
|
305
419
|
brushColourKind,
|
|
420
|
+
brushContracts,
|
|
306
421
|
brushEditorSections,
|
|
307
422
|
brushLibraryGroups,
|
|
308
423
|
changedBrushPaths,
|
|
@@ -178,3 +178,41 @@ export declare function paintProposalGhost(proposal: PaintProposal): {
|
|
|
178
178
|
height: number;
|
|
179
179
|
data: Uint8ClampedArray;
|
|
180
180
|
} | null;
|
|
181
|
+
/** A stroke an agent is painting live, drawn over the canvas until it is painted for real. */
|
|
182
|
+
export interface PaintAgentStroke {
|
|
183
|
+
id: string;
|
|
184
|
+
/** Who paints it (`agent:<id>`). */
|
|
185
|
+
origin: string;
|
|
186
|
+
/** Path in document pixels. */
|
|
187
|
+
points: readonly {
|
|
188
|
+
x: number;
|
|
189
|
+
y: number;
|
|
190
|
+
}[];
|
|
191
|
+
/** #rrggbb */
|
|
192
|
+
color: string;
|
|
193
|
+
/** Line width in document pixels. */
|
|
194
|
+
size: number;
|
|
195
|
+
/** 0..1 (default 0.6). */
|
|
196
|
+
opacity?: number;
|
|
197
|
+
}
|
|
198
|
+
export interface PaintAgentStrokesState {
|
|
199
|
+
strokes: readonly PaintAgentStroke[];
|
|
200
|
+
}
|
|
201
|
+
/** Agent strokes in progress, for `PaintCanvas` (`agentStrokes`) to draw while the user's pen is down. */
|
|
202
|
+
export interface PaintAgentStrokes {
|
|
203
|
+
getState(): PaintAgentStrokesState;
|
|
204
|
+
subscribe(listener: (state: PaintAgentStrokesState) => void): () => void;
|
|
205
|
+
/** Adds or replaces a stroke (by id). */
|
|
206
|
+
set(stroke: PaintAgentStroke): void;
|
|
207
|
+
remove(id: string): void;
|
|
208
|
+
/** Removes every stroke (or those of one origin). */
|
|
209
|
+
clear(origin?: string): void;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Live agent strokes: an agent painting along with the user draws its companion strokes here
|
|
213
|
+
* while the user's stroke is in progress (the editor can't paint two strokes at once), then paints
|
|
214
|
+
* them for real when the user lifts the pen. `PaintCanvas` draws them as soft lines over the canvas.
|
|
215
|
+
*/
|
|
216
|
+
export declare function createPaintAgentStrokes(): PaintAgentStrokes;
|
|
217
|
+
/** An SVG `points` attribute for a live agent stroke. */
|
|
218
|
+
export declare function paintAgentStrokePoints(stroke: PaintAgentStroke): string;
|
|
@@ -178,3 +178,41 @@ export declare function paintProposalGhost(proposal: PaintProposal): {
|
|
|
178
178
|
height: number;
|
|
179
179
|
data: Uint8ClampedArray;
|
|
180
180
|
} | null;
|
|
181
|
+
/** A stroke an agent is painting live, drawn over the canvas until it is painted for real. */
|
|
182
|
+
export interface PaintAgentStroke {
|
|
183
|
+
id: string;
|
|
184
|
+
/** Who paints it (`agent:<id>`). */
|
|
185
|
+
origin: string;
|
|
186
|
+
/** Path in document pixels. */
|
|
187
|
+
points: readonly {
|
|
188
|
+
x: number;
|
|
189
|
+
y: number;
|
|
190
|
+
}[];
|
|
191
|
+
/** #rrggbb */
|
|
192
|
+
color: string;
|
|
193
|
+
/** Line width in document pixels. */
|
|
194
|
+
size: number;
|
|
195
|
+
/** 0..1 (default 0.6). */
|
|
196
|
+
opacity?: number;
|
|
197
|
+
}
|
|
198
|
+
export interface PaintAgentStrokesState {
|
|
199
|
+
strokes: readonly PaintAgentStroke[];
|
|
200
|
+
}
|
|
201
|
+
/** Agent strokes in progress, for `PaintCanvas` (`agentStrokes`) to draw while the user's pen is down. */
|
|
202
|
+
export interface PaintAgentStrokes {
|
|
203
|
+
getState(): PaintAgentStrokesState;
|
|
204
|
+
subscribe(listener: (state: PaintAgentStrokesState) => void): () => void;
|
|
205
|
+
/** Adds or replaces a stroke (by id). */
|
|
206
|
+
set(stroke: PaintAgentStroke): void;
|
|
207
|
+
remove(id: string): void;
|
|
208
|
+
/** Removes every stroke (or those of one origin). */
|
|
209
|
+
clear(origin?: string): void;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Live agent strokes: an agent painting along with the user draws its companion strokes here
|
|
213
|
+
* while the user's stroke is in progress (the editor can't paint two strokes at once), then paints
|
|
214
|
+
* them for real when the user lifts the pen. `PaintCanvas` draws them as soft lines over the canvas.
|
|
215
|
+
*/
|
|
216
|
+
export declare function createPaintAgentStrokes(): PaintAgentStrokes;
|
|
217
|
+
/** An SVG `points` attribute for a live agent stroke. */
|
|
218
|
+
export declare function paintAgentStrokePoints(stroke: PaintAgentStroke): string;
|
|
@@ -204,6 +204,21 @@ export interface PaintLayerInfo {
|
|
|
204
204
|
/** How many live layer effects (glows, shadows, strokes…) it has, when any (`getLayerEffects`). */
|
|
205
205
|
effects?: number;
|
|
206
206
|
}
|
|
207
|
+
/** A live stroke as it is painted (`onStrokeSample`), for agents that paint along with the user. */
|
|
208
|
+
export interface PaintStrokeSample {
|
|
209
|
+
/** `begin`: the pen went down. `points`: new samples. `end`: the stroke was recorded. `cancel`: it was abandoned. */
|
|
210
|
+
phase: 'begin' | 'points' | 'end' | 'cancel';
|
|
211
|
+
layerId: string;
|
|
212
|
+
brush: PaintBrush;
|
|
213
|
+
/** #rrggbb */
|
|
214
|
+
color: string;
|
|
215
|
+
/** Every raw sample so far (document pixels), in order. */
|
|
216
|
+
points: readonly PenPoint[];
|
|
217
|
+
/** The samples this event added (`points` only). */
|
|
218
|
+
added: readonly PenPoint[];
|
|
219
|
+
/** `end`: the recorded stroke's id, or `null` when it painted nothing. */
|
|
220
|
+
strokeId?: string | null;
|
|
221
|
+
}
|
|
207
222
|
/** One change to the paint history, for hosts and change feeds (`onCommit`). */
|
|
208
223
|
export interface PaintCommitEvent {
|
|
209
224
|
/** `execute`: a new undo step. `merge`: folded into the last one (a slider drag). */
|
|
@@ -371,6 +386,7 @@ export declare class PaintEditorController {
|
|
|
371
386
|
private readonly encodeImage;
|
|
372
387
|
private listeners;
|
|
373
388
|
private commitListeners;
|
|
389
|
+
private sampleListeners;
|
|
374
390
|
/** Origins set by `withOrigin`, innermost last. */
|
|
375
391
|
private origins;
|
|
376
392
|
/** `group` in progress: commits fold into one step, recorded when it ends. */
|
|
@@ -433,6 +449,21 @@ export declare class PaintEditorController {
|
|
|
433
449
|
private paperEffectNodeCache;
|
|
434
450
|
constructor(options?: PaintEditorOptions);
|
|
435
451
|
subscribe(listener: () => void): () => void;
|
|
452
|
+
/**
|
|
453
|
+
* Hears the user's live strokes as they are painted (`beginStroke` sessions, not strokes painted
|
|
454
|
+
* from data): when the pen goes down, each batch of samples, and the end or cancel. For agents
|
|
455
|
+
* that paint along in real time. Returns an unsubscribe function.
|
|
456
|
+
*/
|
|
457
|
+
onStrokeSample(listener: (sample: PaintStrokeSample) => void): () => void;
|
|
458
|
+
private notifySample;
|
|
459
|
+
/** The stroke being painted now, or `null`: its layer, brush, colour and samples so far. */
|
|
460
|
+
getLiveStroke(): {
|
|
461
|
+
layerId: string;
|
|
462
|
+
brushId: string;
|
|
463
|
+
brushName: string;
|
|
464
|
+
color: string;
|
|
465
|
+
points: readonly PenPoint[];
|
|
466
|
+
} | null;
|
|
436
467
|
/** Hears each undo step recorded, merged, undone or redone, with who made it. Returns an unsubscribe function. */
|
|
437
468
|
onCommit(listener: (event: PaintCommitEvent) => void): () => void;
|
|
438
469
|
private notifyCommit;
|
|
@@ -204,6 +204,21 @@ export interface PaintLayerInfo {
|
|
|
204
204
|
/** How many live layer effects (glows, shadows, strokes…) it has, when any (`getLayerEffects`). */
|
|
205
205
|
effects?: number;
|
|
206
206
|
}
|
|
207
|
+
/** A live stroke as it is painted (`onStrokeSample`), for agents that paint along with the user. */
|
|
208
|
+
export interface PaintStrokeSample {
|
|
209
|
+
/** `begin`: the pen went down. `points`: new samples. `end`: the stroke was recorded. `cancel`: it was abandoned. */
|
|
210
|
+
phase: 'begin' | 'points' | 'end' | 'cancel';
|
|
211
|
+
layerId: string;
|
|
212
|
+
brush: PaintBrush;
|
|
213
|
+
/** #rrggbb */
|
|
214
|
+
color: string;
|
|
215
|
+
/** Every raw sample so far (document pixels), in order. */
|
|
216
|
+
points: readonly PenPoint[];
|
|
217
|
+
/** The samples this event added (`points` only). */
|
|
218
|
+
added: readonly PenPoint[];
|
|
219
|
+
/** `end`: the recorded stroke's id, or `null` when it painted nothing. */
|
|
220
|
+
strokeId?: string | null;
|
|
221
|
+
}
|
|
207
222
|
/** One change to the paint history, for hosts and change feeds (`onCommit`). */
|
|
208
223
|
export interface PaintCommitEvent {
|
|
209
224
|
/** `execute`: a new undo step. `merge`: folded into the last one (a slider drag). */
|
|
@@ -371,6 +386,7 @@ export declare class PaintEditorController {
|
|
|
371
386
|
private readonly encodeImage;
|
|
372
387
|
private listeners;
|
|
373
388
|
private commitListeners;
|
|
389
|
+
private sampleListeners;
|
|
374
390
|
/** Origins set by `withOrigin`, innermost last. */
|
|
375
391
|
private origins;
|
|
376
392
|
/** `group` in progress: commits fold into one step, recorded when it ends. */
|
|
@@ -433,6 +449,21 @@ export declare class PaintEditorController {
|
|
|
433
449
|
private paperEffectNodeCache;
|
|
434
450
|
constructor(options?: PaintEditorOptions);
|
|
435
451
|
subscribe(listener: () => void): () => void;
|
|
452
|
+
/**
|
|
453
|
+
* Hears the user's live strokes as they are painted (`beginStroke` sessions, not strokes painted
|
|
454
|
+
* from data): when the pen goes down, each batch of samples, and the end or cancel. For agents
|
|
455
|
+
* that paint along in real time. Returns an unsubscribe function.
|
|
456
|
+
*/
|
|
457
|
+
onStrokeSample(listener: (sample: PaintStrokeSample) => void): () => void;
|
|
458
|
+
private notifySample;
|
|
459
|
+
/** The stroke being painted now, or `null`: its layer, brush, colour and samples so far. */
|
|
460
|
+
getLiveStroke(): {
|
|
461
|
+
layerId: string;
|
|
462
|
+
brushId: string;
|
|
463
|
+
brushName: string;
|
|
464
|
+
color: string;
|
|
465
|
+
points: readonly PenPoint[];
|
|
466
|
+
} | null;
|
|
436
467
|
/** Hears each undo step recorded, merged, undone or redone, with who made it. Returns an unsubscribe function. */
|
|
437
468
|
onCommit(listener: (event: PaintCommitEvent) => void): () => void;
|
|
438
469
|
private notifyCommit;
|